<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_卢春城专栏</title><subtitle type="text">.NET &amp; WIN32 API</subtitle><id>http://feed.cnblogs.com/blog/u/31990/rss</id><updated>2012-01-07T15:40:42Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/31990/rss"/><entry><id>http://www.cnblogs.com/lucc/archive/2011/06/30/2093898.html</id><title type="text">使用Hashtable实现简单的关键字过滤</title><summary type="text">这段时间开发一个聊天室，需要使用到关键字过滤的功能，需求如下： 1.将关键字替换成“*”; 2.支持过滤HTML，例如，S&amp;lt;span&amp;gt;B&amp;lt;/span&amp;gt;也要过滤掉。 原本打算使用String.Replace来实现，但是这样的话，如果关键字很多，例如1000个，用以下方式： for(int i=0;i&amp;lt;1000;i++) {  replace…. } 来实现，性能显然很低。因此，换了一种方法，用了Hashtable来提高过滤的性能。大概思路如下： 根据所有关键字建好用Hashtable数据结构，也可以理解为建立索引，之后每次过滤都用这个来进行： 例如，有以下几个关键字</summary><published>2011-06-29T16:09:00Z</published><updated>2011-06-29T16:09:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2011/06/30/2093898.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2011/06/30/2093898.html"/><content type="html">&lt;p&gt;这段时间开发一个聊天室，需要使用到关键字过滤的功能，需求如下：&lt;/p&gt;  &lt;p&gt;1.将关键字替换成“*”;&lt;/p&gt;  &lt;p&gt;2.支持过滤HTML，例如，S&amp;lt;span&amp;gt;B&amp;lt;/span&amp;gt;也要过滤掉。&lt;/p&gt;  &lt;p&gt;原本打算使用String.Replace来实现，但是这样的话，如果关键字很多，例如1000个，用以下方式：&lt;/p&gt;  &lt;p&gt;for(int i=0;i&amp;lt;1000;i++)&lt;/p&gt;  &lt;p&gt;{&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; replace….    &lt;br /&gt;}&lt;/p&gt;  &lt;p&gt;来实现，性能显然很低。因此，换了一种方法，用了Hashtable来提高过滤的性能。大概思路如下：&lt;/p&gt;  &lt;p&gt;根据所有关键字建好用Hashtable数据结构，也可以理解为建立索引，之后每次过滤都用这个来进行：&lt;/p&gt;  &lt;p&gt;例如，有以下几个关键字： SB , SX, Fuck, AB, ABC,那么用于过滤的数据结构如下：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/lucc/201106/201106300008499809.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201106/201106300008494826.png" width="244" height="178" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;上图中每个黑色方框代表一个hashtable，里面的字母就是hashtable的key，每个key都指向另一个hashtable，例如，第一个hashtable中就包含了3个Key，分别是S，A，F。每个关键字中的每个字符都被分散的放到hashtable中。&lt;/p&gt;  &lt;p&gt;下面举例如何过滤&lt;/p&gt;  &lt;p&gt;1.处理字符串 SB：第一个字母在第一级的hashtable中找到，而B也可以在S指向的Hashtable中找到，B指向的Hashtable中包括0，则，SB符合关键字，过滤掉。&lt;/p&gt;  &lt;p&gt;2.处理字符串 SF：虽然S在第一级hashtable中可以找到，但是S指向的hashtable中没有F，所以，SF不是关键字&lt;/p&gt;  &lt;p&gt;具体代码如下：&lt;/p&gt;  &lt;div &gt;   &lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;static&lt;/span&gt; &lt;span &gt;class&lt;/span&gt; FilterWordUtil&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;{&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;    &lt;span &gt;static&lt;/span&gt; Hashtable FilterWords = &lt;span &gt;new&lt;/span&gt; Hashtable();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; AddFilterWord(&lt;span &gt;string&lt;/span&gt; word)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;        Hashtable h = FilterWords;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;        &lt;span &gt;foreach&lt;/span&gt; (&lt;span &gt;char&lt;/span&gt; c &lt;span &gt;in&lt;/span&gt; word.ToUpper())&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  10:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt; (!h.ContainsKey(c)) h[c] = &lt;span &gt;new&lt;/span&gt; Hashtable();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  11:  &lt;/span&gt;            h = h[c] &lt;span &gt;as&lt;/span&gt; Hashtable;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  12:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  13:  &lt;/span&gt;        h[0] = &lt;span &gt;new&lt;/span&gt; Hashtable();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  14:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  15:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  16:  &lt;/span&gt;    &lt;span &gt;static&lt;/span&gt; &lt;span &gt;int&lt;/span&gt; Match(&lt;span &gt;string&lt;/span&gt; content, &lt;span &gt;int&lt;/span&gt; index, &lt;span &gt;out&lt;/span&gt; StringBuilder alt)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  17:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  18:  &lt;/span&gt;        content = content.ToUpper();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  19:  &lt;/span&gt;        alt = &lt;span &gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  20:  &lt;/span&gt;        &lt;span &gt;bool&lt;/span&gt; filterChar = &lt;span &gt;true&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  21:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  22:  &lt;/span&gt;        Hashtable h = FilterWords;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  23:  &lt;/span&gt;        &lt;span &gt;int&lt;/span&gt; i = index;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  24:  &lt;/span&gt;        &lt;span &gt;for&lt;/span&gt; (; i &amp;lt; content.Length; i++)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  25:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  26:  &lt;/span&gt;            &lt;span &gt;char&lt;/span&gt; c = content[i];&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  27:  &lt;/span&gt;            &lt;span &gt;switch&lt;/span&gt; (c)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  28:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  29:  &lt;/span&gt;            &lt;span &gt;case&lt;/span&gt; &lt;span &gt;'&amp;lt;'&lt;/span&gt;:&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  30:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  31:  &lt;/span&gt;                    filterChar = &lt;span &gt;false&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  32:  &lt;/span&gt;                    &lt;span &gt;break&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  33:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  34:  &lt;/span&gt;            &lt;span &gt;case&lt;/span&gt; &lt;span &gt;'&amp;gt;'&lt;/span&gt;:&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  35:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  36:  &lt;/span&gt;                    filterChar = &lt;span &gt;true&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  37:  &lt;/span&gt;                    &lt;span &gt;break&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  38:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  39:  &lt;/span&gt;            &lt;span &gt;case&lt;/span&gt; &lt;span &gt;' '&lt;/span&gt;:&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  40:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  41:  &lt;/span&gt;                    &lt;span &gt;break&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  42:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  43:  &lt;/span&gt;            &lt;span &gt;default&lt;/span&gt;:&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  44:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  45:  &lt;/span&gt;                    &lt;span &gt;if&lt;/span&gt; (filterChar)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  46:  &lt;/span&gt;                    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  47:  &lt;/span&gt;                        &lt;span &gt;if&lt;/span&gt; (h.ContainsKey(c))&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  48:  &lt;/span&gt;                        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  49:  &lt;/span&gt;                            h = h[c] &lt;span &gt;as&lt;/span&gt; Hashtable;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  50:  &lt;/span&gt;                            c = &lt;span &gt;'*'&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  51:  &lt;/span&gt;                        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  52:  &lt;/span&gt;                        &lt;span &gt;else&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  53:  &lt;/span&gt;                        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  54:  &lt;/span&gt;                            &lt;span &gt;if&lt;/span&gt; (!h.ContainsKey(0)) &lt;span &gt;return&lt;/span&gt; -1;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  55:  &lt;/span&gt;                        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  56:  &lt;/span&gt;                    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  57:  &lt;/span&gt;                    &lt;span &gt;break&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  58:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  59:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  60:  &lt;/span&gt;            alt.Append(c);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  61:  &lt;/span&gt;            &lt;span &gt;if&lt;/span&gt; (h.ContainsKey(0)) &lt;span &gt;return&lt;/span&gt; i;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  62:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  63:  &lt;/span&gt;        &lt;span &gt;return&lt;/span&gt; h.ContainsKey(0) ? i : -1;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  64:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  65:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  66:  &lt;/span&gt;    &lt;span &gt;public&lt;/span&gt; &lt;span &gt;static&lt;/span&gt; String Filter(&lt;span &gt;string&lt;/span&gt; content)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  67:  &lt;/span&gt;    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  68:  &lt;/span&gt;        &lt;span &gt;lock&lt;/span&gt; (FilterWords)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  69:  &lt;/span&gt;        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  70:  &lt;/span&gt;            StringBuilder result = &lt;span &gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  71:  &lt;/span&gt;            &lt;span &gt;bool&lt;/span&gt; filterChar = &lt;span &gt;true&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  72:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  73:  &lt;/span&gt;            &lt;span &gt;for&lt;/span&gt; (&lt;span &gt;int&lt;/span&gt; i = 0; i &amp;lt; content.Length; i++)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  74:  &lt;/span&gt;            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  75:  &lt;/span&gt;                &lt;span &gt;char&lt;/span&gt; c = content[i];&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  76:  &lt;/span&gt;                &lt;span &gt;switch&lt;/span&gt; (c)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  77:  &lt;/span&gt;                {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  78:  &lt;/span&gt;                &lt;span &gt;case&lt;/span&gt; &lt;span &gt;'&amp;lt;'&lt;/span&gt;:&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  79:  &lt;/span&gt;                    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  80:  &lt;/span&gt;                        filterChar = &lt;span &gt;false&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  81:  &lt;/span&gt;                        &lt;span &gt;break&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  82:  &lt;/span&gt;                    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  83:  &lt;/span&gt;                &lt;span &gt;case&lt;/span&gt; &lt;span &gt;'&amp;gt;'&lt;/span&gt;:&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  84:  &lt;/span&gt;                    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  85:  &lt;/span&gt;                        filterChar = &lt;span &gt;true&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  86:  &lt;/span&gt;                        &lt;span &gt;break&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  87:  &lt;/span&gt;                    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  88:  &lt;/span&gt;                &lt;span &gt;default&lt;/span&gt;:&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  89:  &lt;/span&gt;                    {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  90:  &lt;/span&gt;                        &lt;span &gt;if&lt;/span&gt; (filterChar)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  91:  &lt;/span&gt;                        {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  92:  &lt;/span&gt;                            StringBuilder temp;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  93:  &lt;/span&gt;                            &lt;span &gt;int&lt;/span&gt; fi = Match(content, i, &lt;span &gt;out&lt;/span&gt; temp);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  94:  &lt;/span&gt;                            &lt;span &gt;if&lt;/span&gt; (fi != -1)&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  95:  &lt;/span&gt;                            {&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  96:  &lt;/span&gt;                                i = fi;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  97:  &lt;/span&gt;                                result.Append(temp);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  98:  &lt;/span&gt;                                &lt;span &gt;continue&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;  99:  &lt;/span&gt;                            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 100:  &lt;/span&gt;                        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 101:  &lt;/span&gt;                        &lt;span &gt;break&lt;/span&gt;;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 102:  &lt;/span&gt;                    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 103:  &lt;/span&gt;                }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 104:  &lt;/span&gt;                result.Append(c);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 105:  &lt;/span&gt;            }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 106:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 107:  &lt;/span&gt;            &lt;span &gt;return&lt;/span&gt; result.ToString();&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 108:  &lt;/span&gt;        }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 109:  &lt;/span&gt;    }&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt; 110:  &lt;/span&gt;}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;测试代码:&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre&gt;&lt;span &gt;   1:  &lt;/span&gt;&lt;span &gt;//添加关键字&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   2:  &lt;/span&gt;FilterWordUtil.AddFilterWord(&lt;span &gt;&amp;quot;SB&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   3:  &lt;/span&gt;FilterWordUtil.AddFilterWord(&lt;span &gt;&amp;quot;SX&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   4:  &lt;/span&gt;FilterWordUtil.AddFilterWord(&lt;span &gt;&amp;quot;fuck&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   5:  &lt;/span&gt;FilterWordUtil.AddFilterWord(&lt;span &gt;&amp;quot;fuck you&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   6:  &lt;/span&gt;FilterWordUtil.AddFilterWord(&lt;span &gt;&amp;quot;天朝&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   7:  &lt;/span&gt;&lt;span &gt;//过滤&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   8:  &lt;/span&gt;&lt;span &gt;string&lt;/span&gt; new_html = FilterWordUtil.Filter(&lt;span &gt;&amp;quot;你是SB,天&amp;lt;span&amp;gt;朝&amp;lt;/span&amp;gt;&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&#xD;
&#xD;
  &lt;pre&gt;&lt;span &gt;   9:  &lt;/span&gt;Console.WriteLine(new_html);&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&#xD;
&#xD;
&lt;p&gt;过滤效果如下： &lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/lucc/201106/201106300008505382.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201106/20110630000850714.png" width="325" height="89" /&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;看到这里，有些读者要担心了，用了这么多的hashtable，会不会占用很多内存？当时也考虑过这问题，测试了1000多个关键字，建数据结构后，内存大概增加了几M，还不算太多。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/lucc/aggbug/2093898.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2011/06/30/2093898.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2011/04/14/2016532.html</id><title type="text">Lesktop开源WebIM 2.2.0.11——增加在线客服功能</title><summary type="text">距离上次在博客园发布Lesktop2.0.2.7已经有几个月了，在这段时间里，又增加了几个小功能，这次的修改主要有：1、支持MSSQL数据库；2、显示在线/离线；3、增加在线客服功能，可将在线客服嵌入到任何网页中。</summary><published>2011-04-14T14:59:00Z</published><updated>2011-04-14T14:59:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2011/04/14/2016532.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2011/04/14/2016532.html"/><content type="html">&lt;p&gt;距离上次在博客园发布Lesktop2.0.2.7已经有几个月了，在这段时间里，又增加了几个小功能，这次的修改主要有：&lt;/p&gt;  &lt;p&gt;1、支持MSSQL数据库；&lt;/p&gt;  &lt;p&gt;2、显示在线/离线；&lt;/p&gt;  &lt;p&gt;3、增加在线客服功能，可将在线客服嵌入到任何网页中。&lt;/p&gt;  &lt;p&gt;下面主要介绍在线客服功能：&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;你可以在任何网站中嵌入在线客服，具体方法如下：&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;1、注册客服人员；&lt;/p&gt;  &lt;p&gt;2、使用客服人员的登陆名，生成嵌入代码，并将代码嵌入插入到要嵌入客服的网页中。嵌入代码格式如下：&lt;/p&gt;  &lt;pre &gt;&lt;span &gt;&amp;lt;!--&lt;/span&gt;&#xD;
&lt;span &gt;嵌入客服系统，系统将在此处生成客服人员的HTML代码&lt;/span&gt;&#xD;
&lt;span &gt;CSR: {客服人员登录名}&lt;/span&gt;&#xD;
&lt;span &gt;--&amp;gt;&lt;/span&gt;&#xD;
&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;script&lt;/span&gt; &lt;span &gt;src&lt;/span&gt;&lt;span &gt;=&amp;quot;&lt;span &gt;{您的主机}&lt;/span&gt;/Lesktop/EmbedCS.ashx?CSR=&lt;span &gt;{客服人员登录名}&lt;/span&gt; &amp;quot;&lt;/span&gt; &lt;span &gt;language&lt;/span&gt;&lt;span &gt;=&amp;quot;javascript&amp;quot;&lt;/span&gt; &lt;span &gt;type&lt;/span&gt;&lt;span &gt;=&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span &gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;script&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;3、系统将在您插入嵌入代码的位置，生成与客服人员相关（显示昵称和在线状态）的链接的HTML代码。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;例如，以下嵌入代码：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201104/201104142300553500.png" width="534" height="257" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;最终生成的效果如下：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201104/201104142300557437.png" width="374" height="201" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;点击生成的链接，将弹出客服系统对话框：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201104/201104142307145679.png" width="566" height="463" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;生成自定义的客服HTML代码&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;嵌入客服代码后，客服系统默认将生成一个A链接（ &lt;font color="#ff0000"&gt;&amp;lt;a …&amp;gt;昵称（状态）&amp;lt;/a&amp;gt;&lt;/font&gt; ），您可以修改&lt;font color="#ff0000"&gt;Lesktop/Core/Embed.js&lt;/font&gt;来生成自定义的HTML代码：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201104/201104142355535907.png" width="686" height="187" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&lt;a href="http://luchuncheng.com/blog/article.aspx?ID=12" target="_blank"&gt;Lesktop演示和下载&lt;/a&gt; [&lt;a href="javascript:StartChat('lucc')"&gt;在线咨询&lt;/a&gt;] &lt;/div&gt;&lt;img src="http://www.cnblogs.com/lucc/aggbug/2016532.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2011/04/14/2016532.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2011/03/20/1989218.html</id><title type="text">在SQL Server中对视图进行增删改</title><summary type="text">本文将介绍在SQL Server中，如何对视图进行增删改。</summary><published>2011-03-19T17:54:00Z</published><updated>2011-03-19T17:54:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2011/03/20/1989218.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2011/03/20/1989218.html"/><content type="html">&lt;p&gt;&lt;a href="http://luchuncheng.com" target="_blank"&gt;Lesktop开源IM&lt;/a&gt;发布以后，有一些网友问及如何在嵌入IM后与自己网站的用户系统整合(&lt;font color="#ff0000"&gt;即如何让嵌入的IM直接使用网站原有的用户数据库，而不需要将已有的用户数据导入到IM的数据库中&lt;/font&gt;)。Lesktop对Users表（存储用户登录名，昵称，密码等信息的表）都是在存储过程中进行增删改的，显然，如果直接去改Users表相关的存储过程是比较麻烦的，&lt;font color="#ff0000"&gt;本文将介绍一种较为简单的方法，在不需要修改存储过程和源代码的情况下整合用户系统&lt;/font&gt;。&lt;/p&gt;  &lt;p&gt;为实现这个目的，&lt;font color="#ff0000"&gt;先介绍一下在SQL SERVER中，如何对视图进行增删改&lt;/font&gt;。假使用户有Name,Remark两项信息，但是没有存放在同一张表中，而是分开存储在两个表UserBase(ID, Name)，UserExtent(ID, Remark)中。&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201103/201103200154436254.png" width="520" height="121" /&gt;&lt;/p&gt;  &lt;p&gt;为使用方便，建立一个视图Users，用于表示用户的完整信息，其定义如下：&lt;/p&gt;  &lt;pre &gt;&lt;span &gt;CREATE&lt;/span&gt; &lt;span &gt;VIEW&lt;/span&gt; [dbo].[Users]&#xD;
&lt;span &gt;as&lt;/span&gt;&#xD;
&lt;span &gt;SELECT&lt;/span&gt; b.ID &lt;span &gt;as&lt;/span&gt; ID, b.Name &lt;span &gt;as&lt;/span&gt; Name, e.Remark &lt;span &gt;as&lt;/span&gt; Remark &#xD;
&lt;span &gt;FROM&lt;/span&gt; UserBase b, UserExtent e &#xD;
&lt;span &gt;WHERE&lt;/span&gt; b.ID = e.ID;&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;现在，我们希望通过Users视图进行增删改实现对UserBase，UserExtent表进行修改。显然，如果对Users直接执行insert，update，delete是不可能的，执行时会发生以下错误：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201103/201103200154432109.png" width="415" height="79" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;在SQL Server中，对视图增删改可以通过触发器来实现，例如我们可以创建一个INSERT触发器，当在视图Users上执行INSERT时，在触发器中实现对UserBase，UserExtent的INSERT操作。在触发器中，&lt;font color="#ff0000"&gt;可以通过名称为inserted的表，获取到新插入的行&lt;/font&gt;，具体代码如下：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span &gt;CREATE&lt;/span&gt; &lt;span &gt;TRIGGER&lt;/span&gt; [dbo].[Users_Insert] &lt;span &gt;ON&lt;/span&gt; [dbo].[Users] INSTEAD &lt;span &gt;OF&lt;/span&gt; INSERT&#xD;
&lt;span &gt;as&lt;/span&gt;&#xD;
&lt;span &gt;declare&lt;/span&gt; @name nvarchar(32), @remark nvarchar(32)&#xD;
&lt;span &gt;declare&lt;/span&gt; ins_cursor &lt;span &gt;cursor&lt;/span&gt;&#xD;
&lt;span &gt;for&lt;/span&gt;&#xD;
&lt;span &gt;select&lt;/span&gt; Name, Remark &lt;span &gt;from&lt;/span&gt; inserted&#xD;
&lt;span &gt;open&lt;/span&gt; ins_cursor&#xD;
&lt;span &gt;fetch&lt;/span&gt; &lt;span &gt;next&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; ins_cursor &lt;span &gt;into&lt;/span&gt; @name, @remark;&#xD;
&lt;span &gt;while&lt;/span&gt;(@@fetch_status = 0)&#xD;
&lt;span &gt;begin&lt;/span&gt;&#xD;
    &lt;font color="#008000"&gt;--读取所有行，并插入&#xD;
&lt;/font&gt;    insert &lt;span &gt;into&lt;/span&gt; UserBase (Name) &lt;span &gt;values&lt;/span&gt; (@name);&#xD;
    insert &lt;span &gt;into&lt;/span&gt; UserExtent(ID, Remark) &lt;span &gt;values&lt;/span&gt; (@@&lt;span &gt;identity&lt;/span&gt;, @remark);&#xD;
    &lt;span &gt;fetch&lt;/span&gt; &lt;span &gt;next&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; ins_cursor &lt;span &gt;into&lt;/span&gt; @name, @remark;&#xD;
&lt;span &gt;end&lt;/span&gt;&#xD;
&lt;span &gt;close&lt;/span&gt; ins_cursor&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;下面我们通过插入两行数据测试触发器：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;font color="#008000"&gt;--清空所有数据&lt;/font&gt;&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; UserExtent;&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; UserBase;&#xD;
&#xD;
&lt;span &gt;create&lt;/span&gt; &lt;span &gt;table&lt;/span&gt; #temp(&#xD;
    name nvarchar(32),&#xD;
    remark nvarchar(32)&#xD;
)&#xD;
insert #temp (name,remark) &lt;span &gt;values&lt;/span&gt; (N&lt;span &gt;'user1'&lt;/span&gt;, N&lt;span &gt;'1'&lt;/span&gt;);&#xD;
insert #temp (name,remark) &lt;span &gt;values&lt;/span&gt; (N&lt;span &gt;'user2'&lt;/span&gt;, N&lt;span &gt;'2'&lt;/span&gt;);&#xD;
&#xD;
&lt;font color="#008000"&gt;--插入两行数据&lt;/font&gt;&#xD;
insert Users(name, remark)&#xD;
&lt;span &gt;select&lt;/span&gt; name,remark &lt;span &gt;from&lt;/span&gt; #temp&#xD;
&#xD;
&lt;span &gt;drop&lt;/span&gt; &lt;span &gt;table&lt;/span&gt; #temp&#xD;
&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; Users;&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; UserBase;&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; UserExtent;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;执行结果如下：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201103/201103200154433189.png" width="262" height="252" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;创建更新触发器，与INSERT触发器类似，受影响的行会保存在inserted中，&lt;font color="#ff0000"&gt;可以从inserted表中获取受影响的行&lt;/font&gt;，并更新UserBase，UserExtent，具体代码如下：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span &gt;CREATE&lt;/span&gt; &lt;span &gt;TRIGGER&lt;/span&gt; [dbo].[Users_Update] &lt;span &gt;ON&lt;/span&gt; [dbo].[Users] INSTEAD &lt;span &gt;OF&lt;/span&gt; &lt;span &gt;UPDATE&lt;/span&gt;&#xD;
&lt;span &gt;as&lt;/span&gt;&#xD;
&lt;span &gt;update&lt;/span&gt; UserExtent&#xD;
&lt;span &gt;set&lt;/span&gt; UserExtent.Remark=ins.Remark&#xD;
&lt;span &gt;from&lt;/span&gt; inserted ins&#xD;
&lt;span &gt;where&lt;/span&gt; UserExtent.ID = ins.ID;&#xD;
&#xD;
&lt;span &gt;update&lt;/span&gt; UserBase&#xD;
&lt;span &gt;set&lt;/span&gt; UserBase.Name=ins.Name&#xD;
&lt;span &gt;from&lt;/span&gt; inserted ins&#xD;
&lt;span &gt;where&lt;/span&gt; UserBase.ID = ins.ID;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;测试代码：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;font color="#008000"&gt;--清空所有数据&lt;/font&gt;&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; UserExtent;&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; UserBase;&#xD;
&lt;font color="#008000"&gt;--插入两行数据&lt;/font&gt;&#xD;
insert Users (name,remark) &lt;span &gt;values&lt;/span&gt; (N&lt;span &gt;'user1'&lt;/span&gt;, N&lt;span &gt;'1'&lt;/span&gt;);&#xD;
insert Users (name,remark) &lt;span &gt;values&lt;/span&gt; (N&lt;span &gt;'user2'&lt;/span&gt;, N&lt;span &gt;'2'&lt;/span&gt;);&#xD;
insert Users (name,remark) &lt;span &gt;values&lt;/span&gt; (N&lt;span &gt;'user3'&lt;/span&gt;, N&lt;span &gt;'2'&lt;/span&gt;);&#xD;
&lt;font color="#008000"&gt;--修改后两行数据&lt;/font&gt;&#xD;
&lt;span &gt;UPDATE&lt;/span&gt; Users &lt;span &gt;set&lt;/span&gt; Remark = N&lt;span &gt;'3'&lt;/span&gt; &lt;span &gt;where&lt;/span&gt; Remark = N&lt;span &gt;'2'&lt;/span&gt;&#xD;
&lt;font color="#008000"&gt;--输出数据&lt;/font&gt;&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; Users;&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; UserBase;&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; UserExtent;&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;测试结果：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201103/201103200154432633.png" width="218" height="300" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;创建删除触发器，在删除的触发器中，&lt;font color="#ff0000"&gt;可以通过deleted表，获取被删除的行&lt;/font&gt;，具体代码如下：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span &gt;CREATE&lt;/span&gt; &lt;span &gt;TRIGGER&lt;/span&gt; [dbo].[Users_Delete] &lt;span &gt;ON&lt;/span&gt; [dbo].[Users] INSTEAD &lt;span &gt;OF&lt;/span&gt; &lt;span &gt;DELETE&lt;/span&gt;&#xD;
&lt;span &gt;as&lt;/span&gt;&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; UserExtent &lt;span &gt;where&lt;/span&gt; ID &lt;span &gt;in&lt;/span&gt; (&lt;span &gt;select&lt;/span&gt; ID &lt;span &gt;from&lt;/span&gt; deleted)&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; UserBase &lt;span &gt;where&lt;/span&gt; ID &lt;span &gt;in&lt;/span&gt; (&lt;span &gt;select&lt;/span&gt; ID &lt;span &gt;from&lt;/span&gt; deleted)&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;测试代码：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;font color="#008000"&gt;--清空所有数据&lt;/font&gt;&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; UserExtent;&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; UserBase;&#xD;
&lt;font color="#008000"&gt;--插入两行数据&lt;/font&gt;&#xD;
insert Users (name,remark) &lt;span &gt;values&lt;/span&gt; (N&lt;span &gt;'user1'&lt;/span&gt;, N&lt;span &gt;'1'&lt;/span&gt;);&#xD;
insert Users (name,remark) &lt;span &gt;values&lt;/span&gt; (N&lt;span &gt;'user2'&lt;/span&gt;, N&lt;span &gt;'2'&lt;/span&gt;);&#xD;
insert Users (name,remark) &lt;span &gt;values&lt;/span&gt; (N&lt;span &gt;'user3'&lt;/span&gt;, N&lt;span &gt;'2'&lt;/span&gt;);&#xD;
&lt;font color="#008000"&gt;--删除后两行数据&lt;/font&gt;&#xD;
&lt;span &gt;delete&lt;/span&gt; &lt;span &gt;from&lt;/span&gt; Users &lt;span &gt;where&lt;/span&gt; Remark = N&lt;span &gt;'2'&lt;/span&gt;&#xD;
&lt;font color="#008000"&gt;--输出数据&lt;/font&gt;&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; Users;&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; UserBase;&#xD;
&lt;span &gt;select&lt;/span&gt; * &lt;span &gt;from&lt;/span&gt; UserExtent;&lt;/pre&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	background-color: #ffffff;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;运行结果：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201103/20110320015444125.png" width="226" height="195" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;上文已介绍了如何对视图进行增删改，接下来将介绍如何通过建立视图并添加增删改触发器实现Lesktop开源IM用户系统的整合。首先介绍一下Lesktop开源IM数据库中&lt;font color="#ff0000"&gt;Users&lt;/font&gt;表的结构：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201103/201103200154446744.png" width="335" height="379" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;假使您的网站的用户表(假使名称为&lt;font color="#ff0000"&gt;MyUserTable&lt;/font&gt;)只有Name,Nickname：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201103/201103200154444236.png" width="337" height="78" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;那么，您可以建立一张扩展表(假使名称为&lt;font color="#ff0000"&gt;UserExtentIM&lt;/font&gt;)，用于存储其他信息：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201103/201103200154443680.png" width="415" height="360" /&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;接下来，您只需要&lt;font color="#ff0000"&gt;把Users表删掉，重新建立一个名称为Users的视图，然后用上文处理Users, UserBase, UserExtent的方法，在Users视图上建好触发器，在触发器中对MyUserTable，UserExtentIM表进行增删改即可&lt;/font&gt;，Lesktop的存储过程对User进行读取和增删改时，将通过触发器自动转换成对MyUserTable，UserExtentIM的操作，因此不需要修改任何存储过程和源代码，当然也不会对你原有的数据库造成影响。&lt;/p&gt;&#xD;
&lt;img src="http://www.cnblogs.com/lucc/aggbug/1989218.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2011/03/20/1989218.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2010/11/24/1886087.html</id><title type="text">WebBrowser介绍——Javascript与C++互操作</title><summary type="text">WebBrowser控件是Microsoft提供的一个用于网页浏览的客户端控件，WebBrowser控件的使用相当广泛，例如很多邮件客户端都是使用可编辑的WebBrowser控件作为写邮件的工具，也有很多软件用WebBrowser控件弹出网页，如qq的个性首页。本文主要探讨在使用WebBrowser时如何实现Javascript与C++的互操作。</summary><published>2010-11-23T16:25:00Z</published><updated>2010-11-23T16:25:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2010/11/24/1886087.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2010/11/24/1886087.html"/><content type="html">&lt;p&gt;WebBrowser控件是Microsoft提供的一个用于网页浏览的客户端控件，WebBrowser控件的使用相当广泛，例如很多邮件客户端都是使用可编辑的WebBrowser控件作为写邮件的工具，也有很多软件用WebBrowser控件弹出网页，如qq的个性首页。关于WebBrowser的应用，也可以参考笔者开发的&lt;a href="http://www.luchuncheng.com" target="_blank"&gt;开源WebIM&lt;/a&gt;，Lesktop开源WebIM提供的IM客户端就是使用WebBrowser实现的：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.luchuncheng.com" target="_blank"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/Windows-Live-Writer/WebBrowser_13676/image_3.png" width="578" height="456" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;微软的MFC和.NET都有WebBrowser控件，这两个控件虽然容易上手，不过由于包装的太好，所以很难深入。因此&lt;font color="#ff0000"&gt;本文介绍的WebBrowser将不使用MFC和.NET，而是使用C++实现SDK的&lt;/font&gt;&lt;font color="#ff0000"&gt;WebBrowser&lt;/font&gt;。&lt;/p&gt;  &lt;p&gt;由于&lt;font color="#ff0000"&gt;本文主要探讨如何实现Javascript与C++的互操作&lt;/font&gt;，对于如何使用SDK实现WebBrowser，本文不做详细介绍，读者可以参考以下这篇文章：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/norsd/archive/2008/09/13/2921389.aspx" target="_blank"&gt;http://blog.csdn.net/norsd/archive/2008/09/13/2921389.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;不过尽管文章中介绍了SDK实现WebBrowser的要点，却没有提供一个可以运行的示例，如果要看到实际的运行效果，可以下载以下这份源代码，源代码中也包括了互操作的演示：&lt;/p&gt;  &#xD;
&#xD;
&lt;div &gt;&#xD;
&lt;a href="http://files.cnblogs.com/lucc/webbrowser.zip"&gt;SDK实现WebBrowser及演示代码&lt;/a&gt;&#xD;
[&lt;a href="javascript:_PostComment(null, true)"&gt;好文，推荐一下&lt;/a&gt;&lt;a href="javascript:_PostComment('看不懂', false)"&gt;看不懂&lt;/a&gt;]&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;1、C++调用WebBrowser中的全局函数，变量等&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;(1) 从C++的角度看WebBrowser中的对象&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;WebBrowser中的对象大致可以分成两类：DOM对象和使用Javascript创建的对象。但是无论是那种对象，从C++的角度来看，都是一些实现了&lt;a href="http://msdn.microsoft.com/en-us/library/ms221608.aspx" target="_blank"&gt;IDispatch&lt;/a&gt;接口的对象，因此，如果用C++操作WebBrowser中的对象（全局函数，变量，DOM）等，只需要通过IDispatch即可。&lt;/p&gt;  &lt;p&gt;&lt;font color="#000000"&gt;&lt;strong&gt;(2) 3个常用的函数&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;当&lt;font color="#ff0000"&gt;获取了WebBrowser的对象的IDispatch接口后，就可以调用IDispatch的Invoke方法来调用对象的方法，获取对象的属性和设置对象的属性&lt;/font&gt;。但是Invoke是通过ID判断要调用指定对象的哪一个方法（或属性），因此在通过方法（或属性）名称调用对象的方法是，必须&lt;font color="#ff0000"&gt;先调用IDispatch的GetIDsOfNames方法，将方法（或属性）名转换成ID&lt;/font&gt;，然后才能通过IDispatch的Invoke方法调用对象的方法。为了方便操作，封装了&lt;font color="#ff0000"&gt;三个函数，分别用于调用WebBrowser的对象的方法，读取对象的属性，设置对象的属性。&lt;/font&gt;&lt;/p&gt;  &lt;div &gt;   &lt;pre &gt;DISPID CWebBrowserBase::FindId(IDispatch *pObj, LPOLESTR pName)&#xD;
{&#xD;
    DISPID id = 0;&#xD;
    &lt;span &gt;if&lt;/span&gt;(FAILED(pObj-&amp;gt;GetIDsOfNames(IID_NULL,&amp;amp;pName,1,LOCALE_SYSTEM_DEFAULT,&amp;amp;id))) id = -1;&#xD;
    &lt;span &gt;return&lt;/span&gt; id;&#xD;
}&#xD;
&#xD;
HRESULT CWebBrowserBase::InvokeMethod(IDispatch *pObj, LPOLESTR pName, VARIANT *pVarResult, VARIANT *p, &lt;span &gt;int&lt;/span&gt; cArgs)&#xD;
{&#xD;
    DISPID dispid = FindId(pObj, pName);&#xD;
    &lt;span &gt;if&lt;/span&gt;(dispid == -1) &lt;span &gt;return&lt;/span&gt; E_FAIL;&#xD;
&#xD;
    DISPPARAMS ps;&#xD;
    ps.cArgs = cArgs;&#xD;
    ps.rgvarg = p;&#xD;
    ps.cNamedArgs = 0;&#xD;
    ps.rgdispidNamedArgs = NULL;&#xD;
&#xD;
    &lt;span &gt;return&lt;/span&gt; pObj-&amp;gt;Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &amp;amp;ps, pVarResult, NULL, NULL);&#xD;
}&#xD;
&#xD;
HRESULT CWebBrowserBase::GetProperty(IDispatch *pObj, LPOLESTR pName, VARIANT *pValue)&#xD;
{&#xD;
    DISPID dispid = FindId(pObj, pName);&#xD;
    &lt;span &gt;if&lt;/span&gt;(dispid == -1) &lt;span &gt;return&lt;/span&gt; E_FAIL;&#xD;
&#xD;
    DISPPARAMS ps;&#xD;
    ps.cArgs = 0;&#xD;
    ps.rgvarg = NULL;&#xD;
    ps.cNamedArgs = 0;&#xD;
    ps.rgdispidNamedArgs = NULL;&#xD;
&#xD;
    &lt;span &gt;return&lt;/span&gt; pObj-&amp;gt;Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &amp;amp;ps, pValue, NULL, NULL);&#xD;
}&#xD;
&#xD;
HRESULT CWebBrowserBase::SetProperty(IDispatch *pObj, LPOLESTR pName, VARIANT *pValue)&#xD;
{&#xD;
    DISPID dispid = FindId(pObj, pName);&#xD;
    &lt;span &gt;if&lt;/span&gt;(dispid == -1) &lt;span &gt;return&lt;/span&gt; E_FAIL;&#xD;
&#xD;
    DISPPARAMS ps;&#xD;
    ps.cArgs = 1;&#xD;
    ps.rgvarg = pValue;&#xD;
    ps.cNamedArgs = 0;&#xD;
    ps.rgdispidNamedArgs = NULL;&#xD;
&#xD;
    &lt;span &gt;return&lt;/span&gt; pObj-&amp;gt;Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &amp;amp;ps, NULL, NULL, NULL);&#xD;
}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;font color="#000000"&gt;&lt;strong&gt;(3)调用页面的全局函数&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;在网页中，&lt;font color="#ff0000"&gt;所有的全局函数均是window的一个方法&lt;/font&gt;，因此，如果要调用全局函数，首先要获取到页面的window对象，然后用InvokeMethod调用全局函数，例如，假设页面中有一个Test全局函数：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;script&lt;/span&gt; &lt;span &gt;language&lt;/span&gt;&lt;span &gt;=&amp;quot;javascript&amp;quot;&lt;/span&gt; &lt;span &gt;type&lt;/span&gt;&lt;span &gt;=&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
&lt;span &gt;function&lt;/span&gt; Test()&#xD;
{&#xD;
    alert(&lt;span &gt;&amp;quot;你调用了Test&amp;quot;&lt;/span&gt;);&#xD;
}&#xD;
&lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;script&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;那么，您可以在C++中用以下代码调用Test函数：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;VARIANT &lt;span &gt;params&lt;/span&gt;[10];&#xD;
VARIANT ret;&#xD;
&lt;span &gt;//获取页面window&lt;/span&gt;&#xD;
IDispatch *pHtmlWindow = pBrowser-&amp;gt;GetHtmlWindow();&#xD;
&lt;span &gt;//页面全局函数Test实际上是window的Test方法，&lt;/span&gt;&#xD;
CWebBrowserBase::InvokeMethod(pHtmlWindow, L&lt;span &gt;&amp;quot;Test&amp;quot;&lt;/span&gt;, &amp;amp;ret, &lt;span &gt;params&lt;/span&gt;, 0);&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;(4)调用全局对象的方法&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;在网页中，&lt;font color="#ff0000"&gt;所有的全局变量均是window的一个属性&lt;/font&gt;，因此，如果要调用变量的方法（或属性），首先要获取到页面的window对象，然后用GetProperty获取到全局变量，然后就可以调用这个对象的方法，或读写其属性。例如，假设页面中有一个globalObject全局变量：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;&amp;lt;&lt;/span&gt;&lt;span &gt;script&lt;/span&gt; &lt;span &gt;language&lt;/span&gt;&lt;span &gt;=&amp;quot;javascript&amp;quot;&lt;/span&gt; &lt;span &gt;type&lt;/span&gt;&lt;span &gt;=&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&#xD;
&lt;span &gt;function&lt;/span&gt; GlobalObject()&#xD;
{&#xD;
    &lt;span &gt;this&lt;/span&gt;.Test=&lt;span &gt;function&lt;/span&gt;()&#xD;
    {&#xD;
        alert(&lt;span &gt;&amp;quot;你调用了GlobalObject.Test&amp;quot;&lt;/span&gt;);&#xD;
    }&#xD;
}&#xD;
&#xD;
&lt;span &gt;var&lt;/span&gt; globalObject = &lt;span &gt;new&lt;/span&gt; GlobalObject();&#xD;
&lt;span &gt;&amp;lt;/&lt;/span&gt;&lt;span &gt;script&lt;/span&gt;&lt;span &gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;那么，您可以使用一下代码调用globalObject的Test方法：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;VARIANT &lt;span &gt;params&lt;/span&gt;[10];&#xD;
VARIANT ret;&#xD;
&lt;span &gt;//获取页面window&lt;/span&gt;&#xD;
IDispatch *pHtmlWindow = pBrowser-&amp;gt;GetHtmlWindow();&#xD;
&lt;span &gt;//获取globalObject&lt;/span&gt;&#xD;
CVariant globalObject;&#xD;
&lt;span &gt;params&lt;/span&gt;[0].vt = VT_BSTR;&#xD;
&lt;span &gt;params&lt;/span&gt;[0].bstrVal = L&lt;span &gt;&amp;quot;globalObject&amp;quot;&lt;/span&gt;;&#xD;
CWebBrowserBase::GetProperty(pHtmlWindow, L&lt;span &gt;&amp;quot;globalObject&amp;quot;&lt;/span&gt;, &amp;amp;globalObject);&#xD;
&lt;span &gt;//调用globalObject.Test&lt;/span&gt;&#xD;
CWebBrowserBase::InvokeMethod(globalObject.pdispVal, L&lt;span &gt;&amp;quot;Test&amp;quot;&lt;/span&gt;, &amp;amp;ret, &lt;span &gt;params&lt;/span&gt;, 0);&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;2、在网页中调用客户端的方法&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;上文我们已经介绍了如何在C++中调用WebBrowser中的对象，接下来，将介绍如何在页面中调用客户端中的函数和对象：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;(1) 通过window.external调用&lt;/strong&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;下面将示例如何通过window.external调用客户端中的函数,假设在C++中定义了一个名为CppCall的函数：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;void&lt;/span&gt; CppCall()&#xD;
{&#xD;
    MessageBox(NULL, L&lt;span &gt;&amp;quot;您调用了CppCall&amp;quot;&lt;/span&gt;, L&lt;span &gt;&amp;quot;提示(C++)&amp;quot;&lt;/span&gt;, 0);&#xD;
}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;定义一个对象，并且实现IDispatch接口：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;class&lt;/span&gt; ClientCall:&lt;span &gt;public&lt;/span&gt; IDispatch&#xD;
{&#xD;
    &lt;span &gt;long&lt;/span&gt; _refNum;&#xD;
&lt;span &gt;public&lt;/span&gt;:&#xD;
    ClientCall()&#xD;
    {&#xD;
        _refNum = 1;&#xD;
    }&#xD;
    ~ClientCall(&lt;span &gt;void&lt;/span&gt;)&#xD;
    {&#xD;
    }&#xD;
&lt;span &gt;public&lt;/span&gt;:&#xD;
&#xD;
    &lt;span &gt;// IUnknown Methods&lt;/span&gt;&#xD;
&#xD;
    STDMETHODIMP QueryInterface(REFIID iid,&lt;span &gt;void&lt;/span&gt;**ppvObject)&#xD;
    {&#xD;
        *ppvObject = NULL;&#xD;
        &lt;span &gt;if&lt;/span&gt; (iid == IID_IUnknown)    *ppvObject = &lt;span &gt;this&lt;/span&gt;;&#xD;
        &lt;span &gt;else&lt;/span&gt; &lt;span &gt;if&lt;/span&gt; (iid == IID_IDispatch)    *ppvObject = (IDispatch*)&lt;span &gt;this&lt;/span&gt;;&#xD;
        &lt;span &gt;if&lt;/span&gt;(*ppvObject)&#xD;
        {&#xD;
            AddRef();&#xD;
            &lt;span &gt;return&lt;/span&gt; S_OK;&#xD;
        }&#xD;
        &lt;span &gt;return&lt;/span&gt; E_NOINTERFACE;&#xD;
    }&#xD;
&#xD;
    STDMETHODIMP_(ULONG) AddRef()&#xD;
    {&#xD;
        &lt;span &gt;return&lt;/span&gt; ::InterlockedIncrement(&amp;amp;_refNum);&#xD;
    }&#xD;
&#xD;
    STDMETHODIMP_(ULONG) Release()&#xD;
    {&#xD;
        ::InterlockedDecrement(&amp;amp;_refNum);&#xD;
        &lt;span &gt;if&lt;/span&gt;(_refNum == 0)&#xD;
        {&#xD;
            delete &lt;span &gt;this&lt;/span&gt;;&#xD;
        }&#xD;
        &lt;span &gt;return&lt;/span&gt; _refNum;&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;// IDispatch Methods&lt;/span&gt;&#xD;
&#xD;
    HRESULT _stdcall GetTypeInfoCount(&#xD;
        unsigned &lt;span &gt;int&lt;/span&gt; * pctinfo) &#xD;
    {&#xD;
        &lt;span &gt;return&lt;/span&gt; E_NOTIMPL;&#xD;
    }&#xD;
&#xD;
    HRESULT _stdcall GetTypeInfo(&#xD;
        unsigned &lt;span &gt;int&lt;/span&gt; iTInfo,&#xD;
        LCID lcid,&#xD;
        ITypeInfo FAR* FAR* ppTInfo) &#xD;
    {&#xD;
        &lt;span &gt;return&lt;/span&gt; E_NOTIMPL;&#xD;
    }&#xD;
&#xD;
    HRESULT _stdcall GetIDsOfNames(&#xD;
        REFIID riid, &#xD;
        OLECHAR FAR* FAR* rgszNames, &#xD;
        unsigned &lt;span &gt;int&lt;/span&gt; cNames, &#xD;
        LCID lcid, &#xD;
        DISPID FAR* rgDispId &#xD;
    )&#xD;
    {&#xD;
        &lt;span &gt;if&lt;/span&gt;(lstrcmp(rgszNames[0], L&lt;span &gt;&amp;quot;CppCall&amp;quot;&lt;/span&gt;)==0)&#xD;
        {&#xD;
            &lt;span &gt;//网页调用window.external.CppCall时，会调用这个方法获取CppCall的ID&lt;/span&gt;&#xD;
            *rgDispId = 100;&#xD;
        }&#xD;
        &lt;span &gt;return&lt;/span&gt; S_OK;&#xD;
    }&#xD;
&#xD;
    HRESULT _stdcall Invoke(&#xD;
        DISPID dispIdMember,&#xD;
        REFIID riid,&#xD;
        LCID lcid,&#xD;
        WORD wFlags,&#xD;
        DISPPARAMS* pDispParams,&#xD;
        VARIANT* pVarResult,&#xD;
        EXCEPINFO* pExcepInfo,&#xD;
        unsigned &lt;span &gt;int&lt;/span&gt;* puArgErr&#xD;
    )&#xD;
    {&#xD;
        &lt;span &gt;if&lt;/span&gt;(dispIdMember == 100)&#xD;
        {&#xD;
            &lt;span &gt;//网页调用CppCall时，或根据获取到的ID调用Invoke方法&lt;/span&gt;&#xD;
            CppCall();&#xD;
        }&#xD;
        &lt;span &gt;return&lt;/span&gt; S_OK;&#xD;
    }&#xD;
};&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;定义类ClientCall后，就可以创建一个ClientCall的对象，传递给WebBrowser，使得网页中可以通过window.external调用CppCall，要实现这些功能，WebBrowser需要实现IDocHostUIHandler接口，并重写GetExternal方法以返回一个ClientCall对象：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;ClientCall *pClientCall;&#xD;
pClientCall = &lt;span &gt;new&lt;/span&gt; ClientCall();&#xD;
&#xD;
&lt;span &gt;virtual&lt;/span&gt; HRESULT STDMETHODCALLTYPE GetExternal(IDispatch **ppDispatch)&#xD;
{&#xD;
    &lt;span &gt;//重写GetExternal返回一个ClientCall对象&lt;/span&gt;&#xD;
    *ppDispatch = pClientCall;&#xD;
    &lt;span &gt;return&lt;/span&gt; S_OK;&#xD;
}&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;接下来，就可以在网页中调用了：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;window.external.CppCall()&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;strong&gt;(2)向网页传递回调函数&lt;/strong&gt; &#xD;
&#xD;
&lt;p&gt;&lt;font color="#ff0000"&gt;向网页传递回调函数的一个典型应用就是在客户端中用C++处理DOM的事件&lt;/font&gt;(例如，处理按钮的onclick事件)，这里要注意的是，与C++不同的是，在网页中，&lt;font color="#ff0000"&gt;所谓的函数，其实就是一个具有call方法的对象&lt;/font&gt;，因此，向网页传递一个回调函数，其实就是传递一个实现了call方法的对象，因此，我们必须定义一个C++类，并实现IDispatch接口：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;typedef &lt;span &gt;void&lt;/span&gt; _stdcall JsFunction_Callback(LPVOID pParam);&#xD;
&#xD;
&lt;span &gt;class&lt;/span&gt; JsFunction:&lt;span &gt;public&lt;/span&gt; IDispatch&#xD;
{&#xD;
    &lt;span &gt;long&lt;/span&gt; _refNum;&#xD;
    JsFunction_Callback *m_pCallback;&#xD;
    LPVOID m_pParam;&#xD;
&lt;span &gt;public&lt;/span&gt;:&#xD;
    JsFunction(JsFunction_Callback *pCallback, LPVOID pParam)&#xD;
    {&#xD;
        _refNum = 1;&#xD;
        m_pCallback = pCallback;&#xD;
        m_pParam = pParam;&#xD;
    }&#xD;
    ~JsFunction(&lt;span &gt;void&lt;/span&gt;)&#xD;
    {&#xD;
    }&#xD;
&lt;span &gt;public&lt;/span&gt;:&#xD;
&#xD;
    &lt;span &gt;// IUnknown Methods&lt;/span&gt;&#xD;
&#xD;
    STDMETHODIMP QueryInterface(REFIID iid,&lt;span &gt;void&lt;/span&gt;**ppvObject)&#xD;
    {&#xD;
        *ppvObject = NULL;&#xD;
&#xD;
        &lt;span &gt;if&lt;/span&gt; (iid == IID_IOleClientSite)    *ppvObject = (IOleClientSite*)&lt;span &gt;this&lt;/span&gt;;&#xD;
        &lt;span &gt;else&lt;/span&gt; &lt;span &gt;if&lt;/span&gt; (iid == IID_IUnknown)    *ppvObject = &lt;span &gt;this&lt;/span&gt;;&#xD;
        &lt;span &gt;if&lt;/span&gt;(*ppvObject)&#xD;
        {&#xD;
            AddRef();&#xD;
            &lt;span &gt;return&lt;/span&gt; S_OK;&#xD;
        }&#xD;
        &lt;span &gt;return&lt;/span&gt; E_NOINTERFACE;&#xD;
    }&#xD;
&#xD;
    STDMETHODIMP_(ULONG) AddRef()&#xD;
    {&#xD;
        &lt;span &gt;return&lt;/span&gt; ::InterlockedIncrement(&amp;amp;_refNum);&#xD;
    }&#xD;
&#xD;
    STDMETHODIMP_(ULONG) Release()&#xD;
    {&#xD;
        ::InterlockedDecrement(&amp;amp;_refNum);&#xD;
        &lt;span &gt;if&lt;/span&gt;(_refNum == 0)&#xD;
        {&#xD;
            delete &lt;span &gt;this&lt;/span&gt;;&#xD;
        }&#xD;
        &lt;span &gt;return&lt;/span&gt; _refNum;&#xD;
    }&#xD;
&#xD;
    &lt;span &gt;// IDispatch Methods&lt;/span&gt;&#xD;
&#xD;
    HRESULT _stdcall GetTypeInfoCount(&#xD;
        unsigned &lt;span &gt;int&lt;/span&gt; * pctinfo) &#xD;
    {&#xD;
        &lt;span &gt;return&lt;/span&gt; E_NOTIMPL;&#xD;
    }&#xD;
&#xD;
    HRESULT _stdcall GetTypeInfo(&#xD;
        unsigned &lt;span &gt;int&lt;/span&gt; iTInfo,&#xD;
        LCID lcid,&#xD;
        ITypeInfo FAR* FAR* ppTInfo) &#xD;
    {&#xD;
        &lt;span &gt;return&lt;/span&gt; E_NOTIMPL;&#xD;
    }&#xD;
&#xD;
    HRESULT _stdcall GetIDsOfNames(&#xD;
        REFIID riid, &#xD;
        OLECHAR FAR* FAR* rgszNames, &#xD;
        unsigned &lt;span &gt;int&lt;/span&gt; cNames, &#xD;
        LCID lcid, &#xD;
        DISPID FAR* rgDispId &#xD;
    )&#xD;
    {&#xD;
        &lt;span &gt;//令人费解的是，网页调用函数的call方法时，没有调用GetIDsOfNames获取call的ID，而是直接调用Invoke&lt;/span&gt;&#xD;
        &lt;span &gt;return&lt;/span&gt; E_NOTIMPL;&#xD;
    }&#xD;
&#xD;
    HRESULT _stdcall Invoke(&#xD;
        DISPID dispIdMember,&#xD;
        REFIID riid,&#xD;
        LCID lcid,&#xD;
        WORD wFlags,&#xD;
        DISPPARAMS* pDispParams,&#xD;
        VARIANT* pVarResult,&#xD;
        EXCEPINFO* pExcepInfo,&#xD;
        unsigned &lt;span &gt;int&lt;/span&gt;* puArgErr&#xD;
    )&#xD;
    {&#xD;
        m_pCallback(m_pParam);&#xD;
        &lt;span &gt;return&lt;/span&gt; S_OK;&#xD;
    }&#xD;
};&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;&#xD;
	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;接下来，我们就可以使用JsFunction向网页传递回调，以下代码用于处理按钮的onclick事件：&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
  &lt;pre &gt;&lt;span &gt;static&lt;/span&gt; &lt;span &gt;void&lt;/span&gt; _stdcall button1_onclick(LPVOID pParam)&#xD;
{&#xD;
    MainForm *pMainForm = (MainForm*)pParam;&#xD;
    MessageBox(pMainForm-&amp;gt;hWnd, L&lt;span &gt;&amp;quot;您点击了button1&amp;quot;&lt;/span&gt;, L&lt;span &gt;&amp;quot;提示(C++)&amp;quot;&lt;/span&gt;, 0);&#xD;
}&#xD;
&#xD;
VARIANT &lt;span &gt;params&lt;/span&gt;[10];&#xD;
&#xD;
&lt;span &gt;//获取window&lt;/span&gt;&#xD;
IDispatch *pHtmlWindow = GetHtmlWindow();&#xD;
&#xD;
&lt;span &gt;//获取document&lt;/span&gt;&#xD;
CVariant document;&#xD;
&lt;span &gt;params&lt;/span&gt;[0].vt = VT_BSTR;&#xD;
&lt;span &gt;params&lt;/span&gt;[0].bstrVal = L&lt;span &gt;&amp;quot;document&amp;quot;&lt;/span&gt;;&#xD;
GetProperty(pHtmlWindow, L&lt;span &gt;&amp;quot;document&amp;quot;&lt;/span&gt;, &amp;amp;document);&#xD;
&#xD;
&lt;span &gt;//获取button1&lt;/span&gt;&#xD;
CVariant button1;&#xD;
&lt;span &gt;params&lt;/span&gt;[0].vt = VT_BSTR;&#xD;
&lt;span &gt;params&lt;/span&gt;[0].bstrVal = L&lt;span &gt;&amp;quot;button1&amp;quot;&lt;/span&gt;;&#xD;
InvokeMethod(document.pdispVal, L&lt;span &gt;&amp;quot;getElementById&amp;quot;&lt;/span&gt;, &amp;amp;button1, &lt;span &gt;params&lt;/span&gt;, 1);&#xD;
&#xD;
&lt;span &gt;//处理button1的onclick事件&lt;/span&gt;&#xD;
&lt;span &gt;params&lt;/span&gt;[0].vt = VT_DISPATCH;&#xD;
&lt;span &gt;params&lt;/span&gt;[0].pdispVal = &lt;span &gt;new&lt;/span&gt; JsFunction(button1_onclick, &lt;span &gt;this&lt;/span&gt;);&#xD;
SetProperty(button1.pdispVal, L&lt;span &gt;&amp;quot;onclick&amp;quot;&lt;/span&gt;, &lt;span &gt;params&lt;/span&gt;);&lt;/pre&gt;&#xD;
&lt;/div&gt;&#xD;
&lt;style type="text/css"&gt;&#xD;
&#xD;
.csharpcode, .csharpcode pre&#xD;
{&#xD;
	font-size: small;&#xD;
	color: black;&#xD;
	font-family: consolas, "Courier New", courier, monospace;	/*white-space: pre;*/&#xD;
}&#xD;
.csharpcode pre { margin: 0em; }&#xD;
.csharpcode .rem { color: #008000; }&#xD;
.csharpcode .kwrd { color: #0000ff; }&#xD;
.csharpcode .str { color: #006080; }&#xD;
.csharpcode .op { color: #0000c0; }&#xD;
.csharpcode .preproc { color: #cc6633; }&#xD;
.csharpcode .asp { background-color: #ffff00; }&#xD;
.csharpcode .html { color: #800000; }&#xD;
.csharpcode .attr { color: #ff0000; }&#xD;
.csharpcode .alt &#xD;
{&#xD;
	background-color: #f4f4f4;&#xD;
	width: 100%;&#xD;
	margin: 0em;&#xD;
}&#xD;
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&#xD;
&#xD;
&lt;p&gt;以上就是笔者开发&lt;a href="http://www.luchuncheng.com"&gt;Lesktop开源WebIM&lt;/a&gt;时使用WebBrowser的经验总结，如有纰漏，敬请指出。&lt;/p&gt;&#xD;
&#xD;
&lt;div &gt;&#xD;
&lt;a href="http://files.cnblogs.com/lucc/webbrowser.zip" target="_blank"&gt;SDK实现WebBrowser及演示代码&lt;/a&gt;&#xD;
[&lt;a href="javascript:_PostComment(null, true)"&gt;好文，推荐一下&lt;/a&gt;&lt;a href="javascript:_PostComment('看不懂', false)"&gt;看不懂&lt;/a&gt;]&#xD;
&lt;/div&gt;&#xD;
&#xD;
&lt;img src="http://www.cnblogs.com/lucc/aggbug/1886087.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2010/11/24/1886087.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2010/09/14/1826236.html</id><title type="text">开源WebOS</title><summary type="text">今天腾讯发布了WebOS风格的WebQQ2.0，只要你拥有一个虚拟空间，使用本文提供的源代码，你也可以部署一个属于自己的WebOS。</summary><published>2010-09-14T11:44:00Z</published><updated>2010-09-14T11:44:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2010/09/14/1826236.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2010/09/14/1826236.html"/><content type="html">&lt;div &gt;&#xD;
&#xD;
&lt;a href="http://files.cnblogs.com/lucc/LOS-1.0.1.30.zip" target="_blank"&gt;源代码下载&lt;/a&gt;&#xD;
&lt;a href="http://webos.lesktop.com" target="_blank"&gt;在线演示&lt;/a&gt;&#xD;
&lt;a&gt;QQ讨论群:25160257&lt;/a&gt;&#xD;
[&lt;a href="javascript:_PostComment(null, true)"&gt;好文，推荐一下&lt;/a&gt;&lt;a href="javascript:_PostComment('看不懂', false)"&gt;看不懂&lt;/a&gt;]&#xD;
&#xD;
 &lt;/div&gt;&#xD;
&#xD;
&lt;p&gt;今天腾讯发布了WebOS风格的WebQQ2.0，只要你拥有一个虚拟空间，使用本文提供的源代码，你也可以部署一个属于自己的WebOS来,效果如下:&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/image_3.png" width="610" height="484" /&gt; &lt;/p&gt;  &lt;p&gt;这个WebOS的功能在&lt;a href="http://www.cnblogs.com/lucc/archive/2010/04/07/1706706.html" target="_blank"&gt;之前的文章&lt;/a&gt;已有介绍过，不在重复，这里主要介绍一个之前没有开放的功能：在线开发。&lt;/p&gt;  &lt;p&gt;&lt;font color="#ff0000"&gt;&lt;strong&gt;这里的在线开发指的是：使用WebOS提供的开发工具，基于WebOS提供的API开发出可以运行于该WebOS的应用程序&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;下面通过几张图片介绍&lt;strong&gt;如何使用开发工具&lt;/strong&gt;：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/2_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="2" border="0" alt="2" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/2_thumb.png" width="639" height="480" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="5" border="0" alt="5" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/5_3.png" width="640" height="475" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="3" border="0" alt="3" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/3_3.png" width="643" height="484" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;点击保存后，&lt;strong&gt;开发工具会生成可执行文件，你可以脱离开发工具直接运行生成的应用程序&lt;/strong&gt;：&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="4" border="0" alt="4" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/4_3.png" width="644" height="479" /&gt; &lt;/p&gt;  &lt;p&gt;这次同时还开发了WebOS上所有应用的源代码（IM，图片浏览，CHM阅读器等等），用admin登录后，可以在/admin/&lt;font color="#ff0000"&gt;Home/Projects&lt;/font&gt;中找到这些应用程序对应的工程文件：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/8.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="8" border="0" alt="8" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/8_thumb.png" width="621" height="480" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;部署指南：&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;1.建立虚拟目录：&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="6" border="0" alt="6" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/6_1.png" width="635" height="489" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;2.添加ISAPI过滤器&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="7" border="0" alt="7" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebOS_11394/7_1.png" width="478" height="444" /&gt; &lt;/p&gt;  &lt;p&gt;3.管理员密码：&lt;/p&gt;  &lt;p&gt;用户名：admin&lt;/p&gt;  &lt;p&gt;密码:admin&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;div &gt;&#xD;
&#xD;
&lt;a href="http://files.cnblogs.com/lucc/LOS-1.0.1.30.zip" target="_blank"&gt;源代码下载&lt;/a&gt;&#xD;
&lt;a href="http://webos.lesktop.com" target="_blank"&gt;在线演示&lt;/a&gt;&#xD;
&lt;a&gt;QQ讨论群:25160257&lt;/a&gt;&#xD;
[&lt;a href="javascript:_PostComment(null, true)"&gt;好文，推荐一下&lt;/a&gt;&lt;a href="javascript:_PostComment('看不懂', false)"&gt;看不懂&lt;/a&gt;]&#xD;
&#xD;
 &lt;/div&gt;&lt;img src="http://www.cnblogs.com/lucc/aggbug/1826236.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2010/09/14/1826236.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2010/09/09/1821869.html</id><title type="text">云骞开源即时通讯软件</title><summary type="text">Lesktop2.0 主要增加了好友列表，消息提示等，当用户登录WebIM后，会自动提示新消息，Lesktop2.0 还提供了桌面客户端，可以同时以Web模式和桌面模式运行。</summary><published>2010-09-08T16:30:00Z</published><updated>2010-09-08T16:30:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2010/09/09/1821869.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2010/09/09/1821869.html"/><content type="html">&lt;p&gt;云骞开源IM是一款使用ASP.NET，Ajax和Comet等技术开发的轻量级IM。主要特点有：&lt;/p&gt;  &lt;p&gt;1、云骞开源IM的服务端实际上就是一个ASP.NET网站，因此不需要使用独立服务器，&lt;strong&gt;仅需要一个支持.NET2.0的Web空间即可将IM部署到互联网上&lt;/strong&gt;。&lt;/p&gt;  &lt;p&gt;2、只需要&lt;strong&gt;拷贝两个文件夹，并在页面中嵌入一行代码&lt;/strong&gt;，就可以将IM集成到自己的网站或企业内部的OA系统中。 &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;源代码下载及嵌入方法请参考：&lt;/strong&gt;&lt;a href="http://www.luchuncheng.com/blog/article.aspx?ID=12" target="_blank"&gt;http://www.luchuncheng.com/blog/article.aspx?ID=12&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;3、可以同时以客户端模式和Web模式运行，两者拥有完全一样的操作界面。&lt;/p&gt;  &lt;p&gt;客户端模式：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.luchuncheng.com/posts/res/desktop_pre.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="桌面模式" border="0" alt="桌面模式" src="http://images.cnblogs.com/cnblogs_com/lucc/201102/201102192332589272.jpg" width="614" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Web模式（兼容IE6,7,8,FireFox,Chrome等主流浏览器）:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.luchuncheng.com/posts/res/webos_pre.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WebOS模式（可嵌入到网页中，支持Firefox,Chorme,IE等主流浏览器）" border="0" alt="WebOS模式（可嵌入到网页中，支持Firefox,Chorme,IE等主流浏览器）" src="http://images.cnblogs.com/cnblogs_com/lucc/201102/20110219233258668.jpg" width="547" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;4、提供了可视化开发工具，以方便您快速开发IM所需的界面和控件，这些界面和控件，可以同时运行于客户端和WEB桌面，不需要编写两套代码。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/lucc/201102/201102192333004091.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201102/201102192333012073.png" width="644" height="464" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;5、消息记录（包括消息中的图片和文件）都存储在服务器上，只要可以上网，随时随地都可以浏览您的消息记录。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/lucc/201102/201102200144076889.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/201102/201102200144073267.png" width="615" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;hr /&gt;  &lt;p&gt;&lt;strong&gt;云骞企业IM&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;云骞企业IM是在开源IM基础上开发的功能更全面的企业版IM，主要的改进有：&lt;/p&gt;  &lt;p&gt;1、优化UI性能：云骞开源IM为了保证客户端更加精简，将界面（一个动态页面）及相关的脚本，图片等放在服务器上，因此打开窗口时需要先访问WEB服务器，启动较慢。企业版将客户端需要的资源存储在本地，以提高常用窗口的启动速度。当然，企业版仍然支持客户端和Web两种模式，仍然支持嵌入到已有的网站中，可以与企业内部的OA系统等集成。&lt;/p&gt;  &lt;p&gt;2、提供在线客服功能，可将客服功能嵌入到其他网站中。&lt;/p&gt;  &lt;p&gt;3、支持局域网内文件传送，离线文件以及群共享等。&lt;/p&gt;  &lt;p&gt;4、支持多人会话。&lt;/p&gt;  &lt;p&gt;5、支持企业组织架构，可支持多部门隶属。&lt;/p&gt;  &lt;p&gt;6、支持自动更新。&lt;/p&gt;  &lt;p&gt;&lt;font color="#ff0000"&gt;企业版试用：&lt;/font&gt;&lt;a href="http://eim.cc/trial.aspx" target="_blank"&gt;http://eim.cc/trial.aspx&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/lucc/aggbug/1821869.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2010/09/09/1821869.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2010/05/27/1745827.html</id><title type="text">一步一步打造WebIM(5)——将WebIM嵌入到页面中</title><summary type="text">在之前的文章中，已经开发了一个简单的WebIM，但是这个WebIM是在独立的页面中的，今天发布的WebIM是一个可以嵌入到自己网页中的版本，你只需添加少量的代码，就可以在页面中嵌入一个WebIM。</summary><published>2010-05-27T14:38:00Z</published><updated>2010-05-27T14:38:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2010/05/27/1745827.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2010/05/27/1745827.html"/><content type="html">&lt;p&gt;在&lt;a href="http://www.cnblogs.com/lucc/category/243015.html" target="_black"&gt;之前的文章&lt;/a&gt;中，已经开发了一个简单的WebIM，但是这个WebIM是在独立的页面中的，今天发布的WebIM是一个可以嵌入到自己网页中的版本，你只需添加少量的代码，就可以在页面中嵌入一个WebIM。&lt;font color="#ff0000"&gt;不过目前这个WebIM的功能比较简单，如果大家有什么需求可以在评论中提出，或通过&lt;/font&gt;&lt;a href="http://www.luchuncheng.cn/Chat.aspx?User=luchuncheng&amp;Nickname=%u5362%u6625%u57CE" target="_blank"&gt;WebIM&lt;/a&gt;&lt;font color="#ff0000"&gt;与我联系&lt;/font&gt;。以后可能还会将&lt;a href="http://www.luchuncheng.cn/bbs.aspx" target="_blank"&gt;云翔在线软件平台&lt;/a&gt;中的网盘等在线应用集成进来。&lt;/p&gt;  &lt;div id="MyAD"&gt;&lt;a href="http://files.cnblogs.com/lucc/WebIM(5).zip"&gt;源代码下载&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;下载源代码后，按以下步骤操作就可以将WebIM嵌入到网页中。&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;1.将Release中的Bin,App_Data和YunXiang三个文件夹拷贝到网站的&lt;font color="#ff0000"&gt;根目录&lt;/font&gt;下。&lt;/p&gt;  &lt;p&gt;2.在将要嵌入WebIM的页面中添加一下引用：&lt;/p&gt;  &lt;pre &gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;link &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;YunXiang/Themes/Default/skin.css&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;rel&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;stylesheet&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;text/css&amp;quot; /&amp;gt;&#xD;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;script &lt;/span&gt;&lt;span style="color: red"&gt;src&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;YunXiang/json2.js&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;script&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&#xD;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;script &lt;/span&gt;&lt;span style="color: red"&gt;src&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;YunXiang/Config.js&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;script&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&#xD;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;script &lt;/span&gt;&lt;span style="color: red"&gt;src&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;YunXiang/Core.js&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;script&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;3.在Global.asax的Application_Start和Application_End中添加以下代码(&lt;font color="#ff0000"&gt;如果没有Global.asax则拷贝Global.asax到网站根目录下&lt;/font&gt;)&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;&lt;span&gt;Application_Start(&lt;/span&gt;&lt;span style="color: blue"&gt;object &lt;/span&gt;&lt;span&gt;sender, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;&lt;span&gt;e) &#xD;
{&#xD;
    &lt;/span&gt;&lt;span style="color: green"&gt;//在应用程序启动时运行的代码&#xD;
    &lt;/span&gt;&lt;span&gt;YunXiang.&lt;/span&gt;&lt;span style="color: #2b91af"&gt;MessageManagement&lt;/span&gt;&lt;span&gt;.Instance.Initialize(Context);&#xD;
}&#xD;
&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;&lt;span&gt;Application_End(&lt;/span&gt;&lt;span style="color: blue"&gt;object &lt;/span&gt;&lt;span&gt;sender, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;&lt;span&gt;e) &#xD;
{&#xD;
    &lt;/span&gt;&lt;span style="color: green"&gt;//在应用程序关闭时运行的代码&#xD;
    &lt;/span&gt;&lt;span&gt;YunXiang.&lt;/span&gt;&lt;span style="color: #2b91af"&gt;MessageManagement&lt;/span&gt;&lt;span&gt;.Instance.Dispose();&#xD;
}&lt;/span&gt;&lt;/pre&gt;&#xD;
4.在web.config的httpHandlers节点中添加以下配置： &#xD;
&#xD;
&lt;pre &gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&#xD;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;add &lt;/span&gt;&lt;span style="color: red"&gt;path&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;Lesktop.aspx&lt;/span&gt;&lt;span&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;verb&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;*&lt;/span&gt;&lt;span&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;YunXiang.Lesktop&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;/&amp;gt;&#xD;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;add &lt;/span&gt;&lt;span style="color: red"&gt;path&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;recevie.aspx&lt;/span&gt;&lt;span&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;verb&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;*&lt;/span&gt;&lt;span&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;YunXiang.WebIM_ReceiveHandler&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;/&amp;gt;&#xD;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;add &lt;/span&gt;&lt;span style="color: red"&gt;path&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;send.aspx&lt;/span&gt;&lt;span&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;verb&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;*&lt;/span&gt;&lt;span&gt;&amp;quot; &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;YunXiang.WebIM_SendHandler&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: blue"&gt;/&amp;gt;&#xD;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;httpHandlers&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;5.将WebIM嵌入到页面中以后，可以通过以下两种方式启动会话：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span&gt;System.StartChat(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;用户名&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;对方的用户名&amp;quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span style="color: green"&gt;//不指定用户，启动时才输入&#xD;
&lt;/span&gt;&lt;span&gt;System.StartChat();&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&#xD;
&#xD;
&lt;p&gt;6.常见问题&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;(1) 嵌入WebIM会影响页面的启动速度吗？&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;由于嵌入WebIM必须引用Core.js文件，因此，嵌入WebIM后，需要多下载几个文件。但是，只要不启动会话，就不会加载和WebIM相关的脚本(Window.js,Controls.js,Desktop.js,WebIM.js等)，只有第一次启动时才会加载。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;(2) WebIM会插入DOM对象吗？&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;只要不启动会话，WebIM不会插入任何DOM对象。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&lt;img src="http://www.cnblogs.com/lucc/aggbug/1745827.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2010/05/27/1745827.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2010/05/25/1743877.html</id><title type="text">一步一步打造WebIM(4)——Comet的特殊之处</title><summary type="text">在一步一步打造WebIM(1)一文中已经使用Comet实现了一个简单的WebIM，那么，Comet究竟和一般的打开网页有何区别，本文将通过编写一个简单的HTTP服务器来说明两者的区别。</summary><published>2010-05-25T12:38:00Z</published><updated>2010-05-25T12:38:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2010/05/25/1743877.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2010/05/25/1743877.html"/><content type="html">&lt;div id="MyAD"&gt; &lt;a href="http://www.luchuncheng.cn/bbs.aspx" target="_blank"&gt;云翔在线聊天室&lt;/a&gt;提供在线聊天室，WebIM，网盘等服务，WebIM可以免费建群（不限人数），聊天记录在线存储。&lt;br/&gt; &lt;/div&gt;&#xD;
&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/category/243015.html" target="_blank"&gt;WebIM系列文章&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;p&gt;在&lt;a href="http://www.cnblogs.com/lucc/archive/2010/04/24/1719397.html"&gt;一步一步打造WebIM(1)&lt;/a&gt;一文中已经使用Comet实现了一个简单的WebIM，那么，Comet究竟和一般的打开网页有何区别，本文将通过编写一个简单的HTTP服务器来说明两者的区别。&lt;/p&gt;  &lt;p&gt;所谓网站，其实可以理解为服务器上的一个应用程序，该应用程序创建了一个Socket并在80端口（一般是80端口）上监听，并接受和处理浏览器发送过来的HTTP请求。&lt;/p&gt;  &lt;p&gt;当你打开网页时，浏览器会发送一个HTTP请求到服务器，之后浏览器将一直等待知道服务器发送完HTTP回应。当服务器接受到这个http请求后，就会解析HTTP请求的头部，根据报文中的信息向浏览器发送数据（网页，图片，数据等），当服务器发送完数据后，浏览器就结束等待，显示出网页。关于浏览器和服务器之前的交互，可以阅读这篇博文：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.cnblogs.com/skynet/archive/2010/05/18/1738301.html" target="_blank"&gt;HTTP协议及其POST与GET操作差异 &amp;amp; C#中如何使用POST、GET等&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;根据以上叙述的交互过程，可以编写一个简单的http服务器，该服务器在8000端口监听，并且只提供两个网页&lt;/p&gt;  &lt;p&gt;&lt;a href="http://localhost:8000/index.htm"&gt;http://localhost:8000/index.htm&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://localhost:8000/comet.htm"&gt;http://localhost:8000/comet.htm&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;这两个网页的区别在于，index.htm服务器在接收到HTTP请求后立刻发送网页并结束本次链接，而Comet.htm则不是如此，是将链接先挂起，并启动一个线程，新的线程将延迟5秒再发送网页。服务器源代码如下：&lt;/p&gt;  &lt;pre &gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;&lt;span&gt;System;&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;&lt;span&gt;System.Collections.Generic;&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;&lt;span&gt;System.Text;&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;&lt;span&gt;System.IO;&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;&lt;span&gt;System.Text.RegularExpressions;&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;&lt;span&gt;System.Net;&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;&lt;span&gt;System.Net.Sockets;&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;&lt;span&gt;System.Threading;&#xD;
&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;namespace &lt;/span&gt;&lt;span&gt;http&#xD;
{&#xD;
    &lt;/span&gt;&lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Program&#xD;
    &lt;/span&gt;&lt;span&gt;{&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;ResponeFormat =&#xD;
        &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;HTTP/1.1 200 OK\r\n&amp;quot; &lt;/span&gt;&lt;span&gt;+&#xD;
        &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Content-Length: {0}\r\n&amp;quot; &lt;/span&gt;&lt;span&gt;+&#xD;
        &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Connection: close\r\n&amp;quot; &lt;/span&gt;&lt;span&gt;+&#xD;
        &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Content-Type: text/html\r\n&amp;quot; &lt;/span&gt;&lt;span&gt;+&#xD;
        &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;\r\n&amp;quot; &lt;/span&gt;&lt;span&gt;+&#xD;
        &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;{1}\r\n&amp;quot;&lt;/span&gt;&lt;span&gt;;&#xD;
&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;static void &lt;/span&gt;&lt;span&gt;Main(&lt;/span&gt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&lt;span&gt;[] args)&#xD;
        {&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Socket &lt;/span&gt;&lt;span&gt;server = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Socket&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #2b91af"&gt;AddressFamily&lt;/span&gt;&lt;span&gt;.InterNetwork, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SocketType&lt;/span&gt;&lt;span&gt;.Stream, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ProtocolType&lt;/span&gt;&lt;span&gt;.Tcp);&#xD;
&#xD;
            &lt;/span&gt;&lt;span style="color: green"&gt;//在8000端口监听&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;EndPoint &lt;/span&gt;&lt;span&gt;ep = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IPEndPoint&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IPAddress&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;new byte&lt;/span&gt;&lt;span&gt;[] { 127, 0, 0, 1 }), 8000);&#xD;
            server.Bind(ep);&#xD;
            server.Listen(5);&#xD;
&#xD;
            &lt;/span&gt;&lt;span style="color: blue"&gt;while &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;true&lt;/span&gt;&lt;span&gt;)&#xD;
            {&#xD;
                &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Socket &lt;/span&gt;&lt;span&gt;client = server.Accept();&#xD;
&#xD;
                &lt;/span&gt;&lt;span style="color: green"&gt;//读取HTTP报文头部&#xD;
                &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;header = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span&gt;.Empty;&#xD;
                &lt;/span&gt;&lt;span style="color: blue"&gt;while &lt;/span&gt;&lt;span&gt;(header.IndexOf(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;\r\n\r\n&amp;quot;&lt;/span&gt;&lt;span&gt;) &amp;lt; 0)&#xD;
                {&#xD;
                    &lt;/span&gt;&lt;span style="color: blue"&gt;byte&lt;/span&gt;&lt;span&gt;[] buffer = &lt;/span&gt;&lt;span style="color: blue"&gt;new byte&lt;/span&gt;&lt;span&gt;[1024];&#xD;
                    &lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;&lt;span&gt;len = client.Receive(buffer);&#xD;
                    header += &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Encoding&lt;/span&gt;&lt;span&gt;.ASCII.GetString(buffer, 0, len);&#xD;
                }&#xD;
&#xD;
                &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;&lt;span&gt;.WriteLine(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;================================================================================&amp;quot;&lt;/span&gt;&lt;span&gt;);&#xD;
                &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;&lt;span&gt;.Write(header);&#xD;
&#xD;
                &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Regex &lt;/span&gt;&lt;span&gt;reg = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Regex&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #a31515"&gt;@&amp;quot;GET\s+([^\s\r\n]+)\s+HTTP/1.1\s*\r\n&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RegexOptions&lt;/span&gt;&lt;span&gt;.IgnoreCase);&#xD;
                &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Match &lt;/span&gt;&lt;span&gt;match = reg.Match(header);&#xD;
                &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(match.Success)&#xD;
                {&#xD;
                    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;fname = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Path&lt;/span&gt;&lt;span&gt;.GetFileName(match.Groups[1].Value).ToLower();&#xD;
&#xD;
                    &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(fname == &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;index.htm&amp;quot;&lt;/span&gt;&lt;span&gt;)&#xD;
                    {&#xD;
                        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;html = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span&gt;.Format(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;&amp;lt;span style='color:red; fonst-size:24px;'&amp;gt;{0}&amp;lt;/span&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;&lt;span&gt;.Now);&#xD;
                        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;response = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span&gt;.Format(ResponeFormat, html.Length, html);&#xD;
&#xD;
                        &lt;/span&gt;&lt;span style="color: green"&gt;//发送HTTP回应，本次HTTP请求结束，浏览器将立刻接受到网页&#xD;
                        &lt;/span&gt;&lt;span&gt;client.Send(&lt;/span&gt;&lt;span style="color: #2b91af"&gt;Encoding&lt;/span&gt;&lt;span&gt;.UTF8.GetBytes(response));&#xD;
                        client.Close();&#xD;
                    }&#xD;
                    &lt;/span&gt;&lt;span style="color: blue"&gt;else if &lt;/span&gt;&lt;span&gt;(fname == &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;comet.htm&amp;quot;&lt;/span&gt;&lt;span&gt;)&#xD;
                    {&#xD;
                        &lt;/span&gt;&lt;span style="color: green"&gt;//假设此时数据未准备好，先挂起链接，网页将在另一个线程中发送到浏览器&#xD;
                        //在线程没有发送HTTP回应前，浏览器将一直等待，直到启动的线程发送回应&#xD;
                        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Thread &lt;/span&gt;&lt;span&gt;thread = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Thread&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ParameterizedThreadStart&lt;/span&gt;&lt;span&gt;(SendThreadEntry));&#xD;
                        thread.Start(client);&#xD;
&#xD;
                    }&#xD;
                    &lt;/span&gt;&lt;span style="color: blue"&gt;else&#xD;
                    &lt;/span&gt;&lt;span&gt;{&#xD;
                        client.Close();&#xD;
                    }&#xD;
                }&#xD;
            }&#xD;
        }&#xD;
&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;static void &lt;/span&gt;&lt;span&gt;SendThreadEntry(&lt;/span&gt;&lt;span style="color: blue"&gt;object &lt;/span&gt;&lt;span&gt;data)&#xD;
        {&#xD;
            &lt;/span&gt;&lt;span style="color: green"&gt;//等待5s&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Thread&lt;/span&gt;&lt;span&gt;.Sleep(5000);&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Socket &lt;/span&gt;&lt;span&gt;client = data &lt;/span&gt;&lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Socket&lt;/span&gt;&lt;span&gt;;&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;html = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span&gt;.Format(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;&amp;lt;span style='color:red; fonst-size:24px;'&amp;gt;{0}&amp;lt;/span&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;&lt;span&gt;.Now);&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;response = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span&gt;.Format(ResponeFormat, html.Length, html);&#xD;
&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;&lt;span&gt;.WriteLine(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;Send Response&amp;quot;&lt;/span&gt;&lt;span&gt;);&#xD;
&#xD;
            &lt;/span&gt;&lt;span style="color: green"&gt;//发送HTTP回应，本次HTTP请求结束，浏览器此时才接收到网页，在此之前浏览器一直等待&#xD;
            &lt;/span&gt;&lt;span&gt;client.Send(&lt;/span&gt;&lt;span style="color: #2b91af"&gt;Encoding&lt;/span&gt;&lt;span&gt;.UTF8.GetBytes(response));&#xD;
            client.Close();&#xD;
        }&#xD;
    }&#xD;
}&lt;/span&gt;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;当然，发送Comet.htm的数据不一定启动一个新的线程，可以先将client保存起来（例如保存到全局变量中），等数据准备好了，调用client的Send方法发送数据。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://files.cnblogs.com/lucc/http.zip"&gt;源代码下载&lt;/a&gt;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;如果本文对您有所帮助，可以点一下推荐&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/lucc/aggbug/1743877.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2010/05/25/1743877.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2010/05/18/1738718.html</id><title type="text">网页信息抓取</title><summary type="text">之前做聊天室时，由于在聊天室中提供了新闻阅读的功能，写了一个从网页中抓取信息（如最新的头条新闻，新闻的来源，标题，内容等）的类，本文将介绍如何使用这个类来抓取网页中需要的信息。</summary><published>2010-05-18T15:16:00Z</published><updated>2010-05-18T15:16:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2010/05/18/1738718.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2010/05/18/1738718.html"/><content type="html">&lt;p&gt;之前做聊天室时，由于在聊天室中提供了新闻阅读的功能，写了一个从网页中抓取信息（如最新的头条新闻，新闻的来源，标题，内容等）的类，本文将介绍如何使用这个类来抓取网页中需要的信息。本文将以抓取博客园首页的博客标题和链接为例：&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/0b78e346b72f_144F3/image_3.png" width="493" height="301" /&gt; &lt;/p&gt;  &lt;p&gt;上图显示的是博客园首页的DOM树，显然只需提取出class为post_item的div，再重中提取出class为titlelnk的a标志即可。这样的功能可以通过以下函数来实现：&lt;/p&gt;  &lt;pre &gt;&lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&#xD;
/// &lt;/span&gt;&lt;span style="color: green"&gt;在文本html的文本查找标志名为tagName,并且属性attrName的值为attrValue的所有标志&#xD;
&lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;例如：FindTagByAttr(html, &amp;quot;div&amp;quot;, &amp;quot;class&amp;quot;, &amp;quot;demo&amp;quot;)&#xD;
&lt;/span&gt;&lt;span style="color: gray"&gt;/// &lt;/span&gt;&lt;span style="color: green"&gt;返回所有class为demo的div标志&#xD;
&lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;&amp;gt; FindTagByAttr(&lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;html, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;tagName, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;attrName, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;attrValue)&#xD;
{&#xD;
    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;format = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span&gt;.Format(&lt;/span&gt;&lt;span style="color: #a31515"&gt;@&amp;quot;&amp;lt;{0}\s[^&amp;lt;&amp;gt;]*{1}\s*=\s*(\x27|\x22){2}(\x27|\x22)[^&amp;lt;&amp;gt;]*&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;, tagName, attrName, attrValue);&#xD;
    &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span&gt;FindTag(html, tagName, format);&#xD;
}&#xD;
&#xD;
&lt;/span&gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;&amp;gt; FindTag(&lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;html, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;name, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;format)&#xD;
{&#xD;
    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Regex &lt;/span&gt;&lt;span&gt;reg = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Regex&lt;/span&gt;&lt;span&gt;(format, &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RegexOptions&lt;/span&gt;&lt;span&gt;.IgnoreCase);&#xD;
    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Regex &lt;/span&gt;&lt;span&gt;tagReg = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Regex&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span&gt;.Format(&lt;/span&gt;&lt;span style="color: #a31515"&gt;@&amp;quot;&amp;lt;(\/|)({0})(\s[^&amp;lt;&amp;gt;]*|)&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;, name), &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RegexOptions&lt;/span&gt;&lt;span&gt;.IgnoreCase);&#xD;
&#xD;
    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;&amp;gt; tags = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;&amp;gt;();&#xD;
    &lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;&lt;span&gt;start = 0;&#xD;
&#xD;
    &lt;/span&gt;&lt;span style="color: blue"&gt;while &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;true&lt;/span&gt;&lt;span&gt;)&#xD;
    {&#xD;
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Match &lt;/span&gt;&lt;span&gt;match = reg.Match(html, start);&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(match.Success)&#xD;
        {&#xD;
            start = match.Index + match.Length;&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Match &lt;/span&gt;&lt;span&gt;tagMatch = &lt;/span&gt;&lt;span style="color: blue"&gt;null&lt;/span&gt;&lt;span&gt;;&#xD;
            &lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;&lt;span&gt;beginTagCount = 1;&#xD;
&#xD;
            &lt;/span&gt;&lt;span style="color: blue"&gt;while &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: blue"&gt;true&lt;/span&gt;&lt;span&gt;)&#xD;
            {&#xD;
                tagMatch = tagReg.Match(html, start);&#xD;
                &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(!tagMatch.Success)&#xD;
                {&#xD;
                    tagMatch = &lt;/span&gt;&lt;span style="color: blue"&gt;null&lt;/span&gt;&lt;span&gt;;&#xD;
                    &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;&lt;span&gt;;&#xD;
                }&#xD;
                start = tagMatch.Index + tagMatch.Length;&#xD;
                &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(tagMatch.Groups[1].Value == &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span&gt;) beginTagCount--;&#xD;
                &lt;/span&gt;&lt;span style="color: blue"&gt;else &lt;/span&gt;&lt;span&gt;beginTagCount++;&#xD;
                &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(beginTagCount == 0) &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;&lt;span&gt;;&#xD;
            }&#xD;
&#xD;
            &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(tagMatch != &lt;/span&gt;&lt;span style="color: blue"&gt;null&lt;/span&gt;&lt;span&gt;)&#xD;
            {&#xD;
                &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag &lt;/span&gt;&lt;span&gt;tag = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;(name, match.Value, html.Substring(match.Index + match.Length, tagMatch.Index - match.Index - match.Length));&#xD;
                tags.Add(tag);&#xD;
            }&#xD;
            &lt;/span&gt;&lt;span style="color: blue"&gt;else&#xD;
            &lt;/span&gt;&lt;span&gt;{&#xD;
                &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;&lt;span&gt;;&#xD;
            }&#xD;
        }&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;else&#xD;
        &lt;/span&gt;&lt;span&gt;{&#xD;
            &lt;/span&gt;&lt;span style="color: blue"&gt;break&lt;/span&gt;&lt;span&gt;;&#xD;
        }&#xD;
    }&#xD;
&#xD;
    &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span&gt;tags;&#xD;
}&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&#xD;
&#xD;
&lt;p&gt;有了以上函数，就可以提取需要的HTML标志了，要实现抓取，还需要一个下载网页的函数：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;GetHtml(&lt;/span&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;&lt;span&gt;url)&#xD;
{&#xD;
    &lt;/span&gt;&lt;span style="color: blue"&gt;try&#xD;
    &lt;/span&gt;&lt;span&gt;{&#xD;
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HttpWebRequest &lt;/span&gt;&lt;span&gt;req = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HttpWebRequest&lt;/span&gt;&lt;span&gt;.Create(url) &lt;/span&gt;&lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HttpWebRequest&lt;/span&gt;&lt;span&gt;;&#xD;
        req.Timeout = 30 * 1000;&#xD;
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HttpWebResponse &lt;/span&gt;&lt;span&gt;response = req.GetResponse() &lt;/span&gt;&lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HttpWebResponse&lt;/span&gt;&lt;span&gt;;&#xD;
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Stream &lt;/span&gt;&lt;span&gt;stream = response.GetResponseStream();&#xD;
&#xD;
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MemoryStream &lt;/span&gt;&lt;span&gt;buffer = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MemoryStream&lt;/span&gt;&lt;span&gt;();&#xD;
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Byte&lt;/span&gt;&lt;span&gt;[] temp = &lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Byte&lt;/span&gt;&lt;span&gt;[4096];&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;&lt;span&gt;count = 0;&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;while &lt;/span&gt;&lt;span&gt;((count = stream.Read(temp, 0, 4096)) &amp;gt; 0)&#xD;
        {&#xD;
            buffer.Write(temp, 0, count);&#xD;
        }&#xD;
&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Encoding&lt;/span&gt;&lt;span&gt;.GetEncoding(response.CharacterSet).GetString(buffer.GetBuffer());&#xD;
    }&#xD;
    &lt;/span&gt;&lt;span style="color: blue"&gt;catch&#xD;
    &lt;/span&gt;&lt;span&gt;{&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;&lt;span&gt;.Empty;&#xD;
    }&#xD;
}&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&#xD;
&#xD;
&lt;p&gt;以下以抓取博客园首页的文章标题和链接为例，介绍如何使用HtmlTag类来抓取网页信息：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;&lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Program&#xD;
&lt;/span&gt;&lt;span&gt;{&#xD;
    &lt;/span&gt;&lt;span style="color: blue"&gt;static void &lt;/span&gt;&lt;span&gt;Main(&lt;/span&gt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&lt;span&gt;[] args)&#xD;
    {&#xD;
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;&lt;span&gt;html = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;.GetHtml(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;http://www.cnblogs.com&amp;quot;&lt;/span&gt;&lt;span&gt;);&#xD;
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;&amp;gt; tags = &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;.FindTagByAttr(html, &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;div&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;post_list&amp;quot;&lt;/span&gt;&lt;span&gt;);&#xD;
        &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(tags.Count &amp;gt; 0)&#xD;
        {&#xD;
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;&amp;gt; item_tags = tags[0].FindTagByAttr(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;div&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;class&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;post_item&amp;quot;&lt;/span&gt;&lt;span&gt;);&#xD;
            &lt;/span&gt;&lt;span style="color: blue"&gt;foreach &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag &lt;/span&gt;&lt;span&gt;item_tag &lt;/span&gt;&lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span&gt;item_tags)&#xD;
            {&#xD;
                &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlTag&lt;/span&gt;&lt;span&gt;&amp;gt; a_tags = item_tag.FindTagByAttr(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;class&amp;quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;titlelnk&amp;quot;&lt;/span&gt;&lt;span&gt;);&#xD;
                &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;&lt;span&gt;(a_tags.Count &amp;gt; 0)&#xD;
                {&#xD;
                    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;&lt;span&gt;.WriteLine(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;标题:{0}&amp;quot;&lt;/span&gt;&lt;span&gt;, a_tags[0].InnerHTML);&#xD;
                    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;&lt;span&gt;.WriteLine(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;链接:{0}&amp;quot;&lt;/span&gt;&lt;span&gt;, a_tags[0].GetAttribute(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;href&amp;quot;&lt;/span&gt;&lt;span&gt;));&#xD;
                    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;&lt;span&gt;.WriteLine(&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;);&#xD;
                }&#xD;
            }&#xD;
        }&#xD;
    }&#xD;
}&lt;/span&gt;&lt;/pre&gt;&#xD;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&#xD;
&#xD;
&lt;p&gt;运行结果如下：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/0b78e346b72f_144F3/image_6.png" width="673" height="442" /&gt; &lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://files.cnblogs.com/lucc/Grad.zip"&gt;源代码下载&lt;/a&gt;&lt;/p&gt;&#xD;
&lt;img src="http://www.cnblogs.com/lucc/aggbug/1738718.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2010/05/18/1738718.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/lucc/archive/2010/05/16/1736537.html</id><title type="text">一步一步打造WebIM(3)——性能测试</title><summary type="text">在一步一步打造WebIM(1)和(2)中，已经讨论了如何开发一个WebIM，并且使用缓存来提高WebIM的性能，本文将编写一个程序模拟大量用户登录来对WebIM进行性能测试。</summary><published>2010-05-15T19:43:00Z</published><updated>2010-05-15T19:43:00Z</updated><author><name>卢春城</name><uri>http://www.cnblogs.com/lucc/</uri></author><link rel="alternate" href="http://www.cnblogs.com/lucc/archive/2010/05/16/1736537.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/lucc/archive/2010/05/16/1736537.html"/><content type="html">&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/category/243015.html" target="_blank"&gt;WebIM系列文章&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;在&lt;a href="http://www.cnblogs.com/lucc/archive/2010/04/24/1719397.html" target="_blank"&gt;一步一步打造WebIM(1)&lt;/a&gt;和&lt;a href="http://www.cnblogs.com/lucc/archive/2010/04/27/1722470.html" target="_blank"&gt;(2)&lt;/a&gt;中，已经讨论了如何开发一个WebIM，并且使用缓存来提高WebIM的性能，本文将编写一个程序模拟大量用户登录来对WebIM进行性能测试。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1.200个用户同时在线&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;测试一将模拟200个用户同时登录的聊天室，每个用户以&lt;font color="#ff0000"&gt;1条消息/秒&lt;/font&gt;的速度发送消息(&lt;font color="#ff0000"&gt;由于网络和服务器处理延迟，可能多于1秒&lt;/font&gt;)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;环境参数&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;操作系统:Window Server 2003&lt;/p&gt;  &lt;p&gt;内存:2G&lt;/p&gt;  &lt;p&gt;CPU:AMD Athlon(tm) 64 X2 Dual 2.4GHz&lt;/p&gt;  &lt;p&gt;服务器:IIS6&lt;/p&gt;  &lt;p&gt;数据库:SQLite&lt;/p&gt;  &lt;p&gt;消息缓存数量:200&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;测试过程截图&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="1" border="0" alt="1" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebIM3_329D/15.jpg" width="604" height="351" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="2" border="0" alt="2" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebIM3_329D/25.jpg" width="604" height="352" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;测试结果&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="200" border="0" alt="200" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebIM3_329D/200_1.png" width="528" height="243" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;测试结果解析&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;测试程序启动了200个接收线程和200个发送线程(以&lt;font color="#ff0000"&gt;1条消息/秒&lt;/font&gt;的速度发送消息，连续发50条)，根据测试结果显示，发送消息的平均延迟大概为1000ms（&lt;font color="#ff0000"&gt;即从客户端发送消息到服务器将消息写到缓存中大概要1000ms&lt;/font&gt;），接收消息的平均延迟为大概600ms（&lt;font color="#ff0000"&gt;服务器将消息写到缓存600ms后，用户才在浏览器中接收到该消息&lt;/font&gt;）。&lt;font color="#ff0000"&gt;由于每一个用户都会接受到其它199个用户的消息，因此，200个接受线程如果消息完全接收，应该有200*50*200 = 2000000条消息&lt;/font&gt;，显然，当发送消息的200个线程结束时，接收消息的线程仍然没有结束。由于发送消息的平均延迟大概为1000ms，因此，相当于200个用户同时以&lt;font color="#ff0000"&gt;1条消息/2秒&lt;/font&gt;的频率向聊天室发送消息。&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2.500个用户同时在线&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;测试一将模拟500个用户同时登录的聊天室，每个用户以&lt;font color="#ff0000"&gt;1条消息/秒&lt;/font&gt;的速度发送消息(&lt;font color="#ff0000"&gt;由于网络和服务器处理延迟，可能多于1秒&lt;/font&gt;)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;环境参数&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;操作系统:Window Server 2003&lt;/p&gt;  &lt;p&gt;内存:2G&lt;/p&gt;  &lt;p&gt;CPU:AMD Athlon(tm) 64 X2 Dual 2.4GHz&lt;/p&gt;  &lt;p&gt;服务器:IIS6&lt;/p&gt;  &lt;p&gt;数据库:SQLite&lt;/p&gt;  &lt;p&gt;消息缓存数量:200&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;测试过程截图&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="3" border="0" alt="3" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebIM3_329D/3_3.jpg" width="604" height="339" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;测试结果&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="500" border="0" alt="500" src="http://images.cnblogs.com/cnblogs_com/lucc/WindowsLiveWriter/WebIM3_329D/500_1.png" width="528" height="211" /&gt; &lt;/p&gt;  &lt;p&gt;测试结果的意义和测试1类似，因此不做详细解析&lt;/p&gt;  &lt;p&gt;&lt;font color="#ff0000"&gt;从以上测试来看，同时在线人数达到500时，延迟还是比较大的&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://files.cnblogs.com/lucc/WebIM(3).zip"&gt;测试程序及WebIM源代码下载&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/lucc/aggbug/1736537.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/lucc/archive/2010/05/16/1736537.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
