﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Dark Angle-随笔分类-Visual C++</title><link>http://www.cppblog.com/niewenlong/category/4916.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 22 Mar 2013 13:42:16 GMT</lastBuildDate><pubDate>Fri, 22 Mar 2013 13:42:16 GMT</pubDate><ttl>60</ttl><item><title>C++的Json解析库：jsoncpp和boost </title><link>http://www.cppblog.com/niewenlong/archive/2013/03/22/198718.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Fri, 22 Mar 2013 05:53:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2013/03/22/198718.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/198718.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2013/03/22/198718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/198718.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/198718.html</trackback:ping><description><![CDATA[<p><span style="font-size: 13px"><strong>JSON</strong>(JavaScript Object Notation)跟xml一样也是一种数据交换格式，了解json请参考其官网<a href="http://json.org/">http://json.org</a>，本文不再对json做介绍，将重点介绍c++的json解析库的使用方法。json官网上列出了各种语言对应的json解析库，作者仅介绍自己使用过的两种C++的json解析库:jsoncpp(v0.5.0)和Boost(v1.34.0)。</span></p>
<h3><a name="t0"></a>&nbsp;一. 使用jsoncpp解析json</h3>
<p><span style="font-size: 13px">Jsoncpp是个跨平台的开源库，首先从</span><a href="http://jsoncpp.sourceforge.net/"><span style="font-size: 13px">http://jsoncpp.sourceforge.net/</span></a><span style="font-size: 13px">上下载jsoncpp库源码，我下载的是v0.5.0，压缩包大约107K，解压，在jsoncpp-src-0.5.0/makefiles/vs71目录里找到jsoncpp.sln，用VS2003及以上版本编译，默认生成静态链接库。 在工程中引用，只需要include/json及.lib文件即可。</span></p>
<p><span style="font-size: 13px">&nbsp;使用JsonCpp前先来熟悉几个主要的类：&nbsp;</span></p>
<p><span style="font-size: 13px">Json::Value &nbsp; &nbsp; 可以表示里所有的类型，比如int,string,object,array等，具体应用将会在后边示例中介绍。</span></p>
<p><span style="font-size: 13px">Json::Reader&nbsp;&nbsp; 将json文件流或字符串解析到Json::Value, 主要函数有Parse。</span></p>
<p><span style="font-size: 13px">Json::Writer &nbsp; &nbsp;与Json::Reader相反，将Json::Value转化成字符串流，注意它的两个子类：Json::FastWriter和Json::StyleWriter，分别输出不带格式的json和带格式的json。</span></p>
<p><span style="font-size: 13px">&nbsp;1. 从字符串解析json</span></p><span style="font-size: 10px"></span>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="datatypes">int</span><span>&nbsp;ParseJsonFromString()&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">const</span><span>&nbsp;</span><span class="datatypes">char</span><span>*&nbsp;str&nbsp;=&nbsp;</span><span class="string">"{\"uploadid\":&nbsp;\"UP000000\",\"code\":&nbsp;100,\"msg\":&nbsp;\"\",\"files\":&nbsp;\"\"}"</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;Json::Reader&nbsp;reader;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;Json::Value&nbsp;root;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(reader.parse(str,&nbsp;root))&nbsp;&nbsp;</span><span class="comment">//&nbsp;reader将Json字符串解析到root，root将包含Json里所有子元素</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;upload_id&nbsp;=&nbsp;root[<span class="string">"uploadid"</span><span>].asString();&nbsp;&nbsp;</span><span class="comment">//&nbsp;访问节点，upload_id&nbsp;=&nbsp;"UP000000"</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;code&nbsp;=&nbsp;root[</span><span class="string">"code"</span><span>].asInt();&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;访问节点，code&nbsp;=&nbsp;100</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;0;&nbsp;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">int ParseJsonFromString()
{
  const char* str = "{\"uploadid\": \"UP000000\",\"code\": 100,\"msg\": \"\",\"files\": \"\"}";

  Json::Reader reader;
  Json::Value root;
  if (reader.parse(str, root))  // reader将Json字符串解析到root，root将包含Json里所有子元素
  {
    std::string upload_id = root["uploadid"].asString();  // 访问节点，upload_id = "UP000000"
    int code = root["code"].asInt();    // 访问节点，code = 100
  }
  return 0;
}</pre>
<p><span style="font-size: 13px">2. 从文件解析json</span></p>
<p><span style="font-size: 13px">json文件内容：</span></p>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span>{&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"uploadid"</span><span>:&nbsp;</span><span class="string">"UP000000"</span><span>,&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"code"</span><span>:&nbsp;</span><span class="string">"0"</span><span>,&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"msg"</span><span>:&nbsp;</span><span class="string">""</span><span>,&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"files"</span><span>:&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;[&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"code"</span><span>:&nbsp;</span><span class="string">"0"</span><span>,&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"msg"</span><span>:&nbsp;</span><span class="string">""</span><span>,&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"filename"</span><span>:&nbsp;</span><span class="string">"1D_16-35_1.jpg"</span><span>,&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"filesize"</span><span>:&nbsp;</span><span class="string">"196690"</span><span>,&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"width"</span><span>:&nbsp;</span><span class="string">"1024"</span><span>,&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"height"</span><span>:&nbsp;</span><span class="string">"682"</span><span>,&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"images"</span><span>:&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"url"</span><span>:&nbsp;</span><span class="string">"fmn061/20111118"</span><span>,&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"type"</span><span>:&nbsp;</span><span class="string">"large"</span><span>,&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"width"</span><span>:&nbsp;</span><span class="string">"720"</span><span>,&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"height"</span><span>:&nbsp;</span><span class="string">"479"</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"url"</span><span>:&nbsp;</span><span class="string">"fmn061/20111118"</span><span>,&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"type"</span><span>:&nbsp;</span><span class="string">"main"</span><span>,&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"width"</span><span>:&nbsp;</span><span class="string">"200"</span><span>,&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="string">"height"</span><span>:&nbsp;</span><span class="string">"133"</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;]&nbsp;&nbsp;</span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">{
    "uploadid": "UP000000",
    "code": "0",
    "msg": "",
    "files":
    [
        {
            "code": "0",
            "msg": "",
            "filename": "1D_16-35_1.jpg",
            "filesize": "196690",
            "width": "1024",
            "height": "682",
            "images":
            [
                {
                    "url": "fmn061/20111118",
                    "type": "large",
                    "width": "720",
                    "height": "479"
                },
                {
                    "url": "fmn061/20111118",
                    "type": "main",
                    "width": "200",
                    "height": "133"
                }
            ]
        }
    ]
}</pre>
<p><span style="font-size: 13px">&nbsp;解析代码：</span></p>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="datatypes">int</span><span>&nbsp;ParseJsonFromFile(</span><span class="keyword">const</span><span>&nbsp;</span><span class="datatypes">char</span><span>*&nbsp;filename)&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="comment">//&nbsp;解析json用Json::Reader</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;Json::Reader&nbsp;reader;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="comment">//&nbsp;Json::Value是一种很重要的类型，可以代表任意类型。如int,&nbsp;string,&nbsp;object,&nbsp;array...</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;Json::Value&nbsp;root;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;std::ifstream&nbsp;is;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;is.open&nbsp;(filename,&nbsp;std::ios::binary&nbsp;);&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(reader.parse(is,&nbsp;root))&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;code;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(!root[</span><span class="string">"files"</span><span>].isNull())&nbsp;&nbsp;</span><span class="comment">//&nbsp;访问节点，Access&nbsp;an&nbsp;object&nbsp;value&nbsp;by&nbsp;name,&nbsp;create&nbsp;a&nbsp;null&nbsp;member&nbsp;if&nbsp;it&nbsp;does&nbsp;not&nbsp;exist.</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code&nbsp;=&nbsp;root[<span class="string">"uploadid"</span><span>].asString();&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;访问节点，Return&nbsp;the&nbsp;member&nbsp;named&nbsp;key&nbsp;if&nbsp;it&nbsp;exist,&nbsp;defaultValue&nbsp;otherwise.</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;code&nbsp;=&nbsp;root.get(<span class="string">"uploadid"</span><span>,&nbsp;</span><span class="string">"null"</span><span>).asString();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;得到"files"的数组个数</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;file_size&nbsp;=&nbsp;root[</span><span class="string">"files"</span><span>].size();&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;遍历数组</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;file_size;&nbsp;++i)&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Json::Value&nbsp;val_image&nbsp;=&nbsp;root[<span class="string">"files"</span><span>][i][</span><span class="string">"images"</span><span>];&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;image_size&nbsp;=&nbsp;val_image.size();&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span>&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;image_size;&nbsp;++j)&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;type&nbsp;=&nbsp;val_image[j][<span class="string">"type"</span><span>].asString();&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;url&nbsp;=&nbsp;val_image[j][<span class="string">"url"</span><span>].asString();&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;is.close();&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;0;&nbsp;&nbsp;</span></span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">int ParseJsonFromFile(const char* filename)
{
  // 解析json用Json::Reader
  Json::Reader reader;
  // Json::Value是一种很重要的类型，可以代表任意类型。如int, string, object, array...
  Json::Value root;       

  std::ifstream is;
  is.open (filename, std::ios::binary );  
  if (reader.parse(is, root))
  {
    std::string code;
    if (!root["files"].isNull())  // 访问节点，Access an object value by name, create a null member if it does not exist.
      code = root["uploadid"].asString();
    
    // 访问节点，Return the member named key if it exist, defaultValue otherwise.
    code = root.get("uploadid", "null").asString();

    // 得到"files"的数组个数
    int file_size = root["files"].size();

    // 遍历数组
    for(int i = 0; i &lt; file_size; ++i)
    {
      Json::Value val_image = root["files"][i]["images"];
      int image_size = val_image.size();
      for(int j = 0; j &lt; image_size; ++j)
      {
        std::string type = val_image[j]["type"].asString();
        std::string url = val_image[j]["url"].asString();
      }
    }
  }
  is.close();
  return 0;
}</pre>
<p><span style="font-size: 13px">&nbsp;3. 在json结构中插入json</span></p><span style="font-size: 10px"></span>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span>Json::Value&nbsp;arrayObj;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;构建对象</span><span>&nbsp;&nbsp;</span></li><li><span>Json::Value&nbsp;new_item,&nbsp;new_item1;&nbsp;&nbsp;</span></li><li class="alt"><span>new_item[<span class="string">"date"</span><span>]&nbsp;=&nbsp;</span><span class="string">"2011-12-28"</span><span>;&nbsp;&nbsp;</span></span></li><li><span>new_item1[<span class="string">"time"</span><span>]&nbsp;=&nbsp;</span><span class="string">"22:30:36"</span><span>;&nbsp;&nbsp;</span></span></li><li class="alt"><span>arrayObj.append(new_item);&nbsp;&nbsp;<span class="comment">//&nbsp;插入数组成员</span><span>&nbsp;&nbsp;</span></span></li><li><span>arrayObj.append(new_item1);&nbsp;<span class="comment">//&nbsp;插入数组成员</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span class="datatypes">int</span><span>&nbsp;file_size&nbsp;=&nbsp;root[</span><span class="string">"files"</span><span>].size();&nbsp;&nbsp;</span></li><li><span class="keyword">for</span><span>(</span><span class="datatypes">int</span><span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;file_size;&nbsp;++i)&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;root[<span class="string">"files"</span><span>][i][</span><span class="string">"exifs"</span><span>]&nbsp;=&nbsp;arrayObj;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;插入原json中</span><span>&nbsp;&nbsp;</span></span></li></ol></div><pre class="cpp" style="display: none" name="code">    Json::Value arrayObj;   // 构建对象
    Json::Value new_item, new_item1;
    new_item["date"] = "2011-12-28";
    new_item1["time"] = "22:30:36";
    arrayObj.append(new_item);  // 插入数组成员
    arrayObj.append(new_item1); // 插入数组成员
    int file_size = root["files"].size();
    for(int i = 0; i &lt; file_size; ++i)
      root["files"][i]["exifs"] = arrayObj;   // 插入原json中</pre>
<p><span style="font-size: 13px">&nbsp;4. 输出json</span></p>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="comment">//&nbsp;转换为字符串（带格式）</span><span>&nbsp;&nbsp;</span></li><li><span>std::string&nbsp;out&nbsp;=&nbsp;root.toStyledString();&nbsp;&nbsp;</span></li><li class="alt"><span class="comment">//&nbsp;输出无格式json字符串</span><span>&nbsp;&nbsp;</span></li><li><span>Json::FastWriter&nbsp;writer;&nbsp;&nbsp;</span></li><li class="alt"><span>std::string&nbsp;out2&nbsp;=&nbsp;writer.write(root);&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">// 转换为字符串（带格式）
std::string out = root.toStyledString();
// 输出无格式json字符串
Json::FastWriter writer;
std::string out2 = writer.write(root);</pre>
<h3><a name="t1"></a>二. 使用Boost property_tree解析json</h3>
<p>property_tree可以解析xml，json，ini，info等格式的数据，用property_tree解析这几种格式使用方法很相似。</p>
<p>解析json很简单，命名空间为boost::property_tree，reson_json函数将文件流、字符串解析到ptree，write_json将ptree输出为字符串或文件流。其余的都是对ptree的操作。</p>
<p>解析json需要加头文件：</p>
<p>#include &lt;boost/property_tree/ptree.hpp&gt;<br />#include &lt;boost/property_tree/json_parser.hpp&gt;</p>
<p>1. 解析json</p>
<p>解析一段下面的数据：</p>
<div class="dp-highlighter bg_html">
<div class="bar">
<div class="tools"><strong>[html]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-xml"><li class="alt"><span>{&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;"code":&nbsp;0,&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;"images":&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;[&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"url":&nbsp;"fmn057/20111221/1130/head_kJoO_05d9000251de125c.jpg"&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"url":&nbsp;"fmn057/20111221/1130/original_kJoO_05d9000251de125c.jpg"&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;]&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="html" style="display: none" name="code">{
  "code": 0,
  "images":
  [
    {
      "url": "fmn057/20111221/1130/head_kJoO_05d9000251de125c.jpg"
    },
    {
      "url": "fmn057/20111221/1130/original_kJoO_05d9000251de125c.jpg"
    }
  ]
}</pre>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="datatypes">int</span><span>&nbsp;ParseJson()&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;std::string&nbsp;str&nbsp;=&nbsp;<span class="string">"{\"code\":0,\"images\":[{\"url\":\"fmn057/20111221/1130/head_kJoO_05d9000251de125c.jpg\"},{\"url\":\"fmn057/20111221/1130/original_kJoO_05d9000251de125c.jpg\"}]}"</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;<span class="keyword">using</span><span>&nbsp;</span><span class="keyword">namespace</span><span>&nbsp;boost::property_tree;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;std::stringstream&nbsp;ss(str);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;ptree&nbsp;pt;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;<span class="keyword">try</span><span>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;read_json(ss,&nbsp;pt);&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">catch</span><span>(ptree_error&nbsp;&amp;&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;1;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">try</span><span>{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;code&nbsp;=&nbsp;pt.get&lt;</span><span class="datatypes">int</span><span>&gt;(</span><span class="string">"code"</span><span>);&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;得到"code"的value</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;ptree&nbsp;image_array&nbsp;=&nbsp;pt.get_child(<span class="string">"images"</span><span>);&nbsp;&nbsp;</span><span class="comment">//&nbsp;get_child得到数组对象</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;遍历数组</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;BOOST_FOREACH(boost::property_tree::ptree::value_type&nbsp;&amp;v,&nbsp;image_array)&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::stringstream&nbsp;s;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write_json(s,&nbsp;v.second);&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;std::string&nbsp;image_item&nbsp;=&nbsp;s.str();&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">catch</span><span>&nbsp;(ptree_error&nbsp;&amp;&nbsp;e)&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;2;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;0;&nbsp;&nbsp;</span></span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">int ParseJson()
{
  std::string str = "{\"code\":0,\"images\":[{\"url\":\"fmn057/20111221/1130/head_kJoO_05d9000251de125c.jpg\"},{\"url\":\"fmn057/20111221/1130/original_kJoO_05d9000251de125c.jpg\"}]}";
  using namespace boost::property_tree;

  std::stringstream ss(str);
  ptree pt;
  try{    
    read_json(ss, pt);
  }
  catch(ptree_error &amp; e) {
    return 1; 
  }

  try{
    int code = pt.get&lt;int&gt;("code");   // 得到"code"的value
    ptree image_array = pt.get_child("images");  // get_child得到数组对象
    
    // 遍历数组
    BOOST_FOREACH(boost::property_tree::ptree::value_type &amp;v, image_array)
    {
      std::stringstream s;
      write_json(s, v.second);
      std::string image_item = s.str();
    }
  }
  catch (ptree_error &amp; e)
  {
    return 2;
  }
  return 0;
}</pre>
<p>2. 构造json</p>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/hzyong_c/article/details/7163589#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="datatypes">int</span><span>&nbsp;InsertJson()&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;std::string&nbsp;str&nbsp;=&nbsp;<span class="string">"{\"code\":0,\"images\":[{\"url\":\"fmn057/20111221/1130/head_kJoO_05d9000251de125c.jpg\"},{\"url\":\"fmn057/20111221/1130/original_kJoO_05d9000251de125c.jpg\"}]}"</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;<span class="keyword">using</span><span>&nbsp;</span><span class="keyword">namespace</span><span>&nbsp;boost::property_tree;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;std::stringstream&nbsp;ss(str);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;ptree&nbsp;pt;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;<span class="keyword">try</span><span>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;read_json(ss,&nbsp;pt);&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">catch</span><span>(ptree_error&nbsp;&amp;&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;1;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="comment">//&nbsp;修改/增加一个key-value，key不存在则增加</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;pt.put(<span class="string">"upid"</span><span>,&nbsp;</span><span class="string">"00001"</span><span>);&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;<span class="comment">//&nbsp;插入一个数组</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;ptree&nbsp;exif_array;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;ptree&nbsp;array1,&nbsp;array2,&nbsp;array3;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;array1.put(<span class="string">"Make"</span><span>,&nbsp;</span><span class="string">"NIKON"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;array2.put(<span class="string">"DateTime"</span><span>,&nbsp;</span><span class="string">"2011:05:31&nbsp;06:47:09"</span><span>);&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;array3.put(<span class="string">"Software"</span><span>,&nbsp;</span><span class="string">"Ver.1.01"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;exif_array.push_back(std::make_pair(<span class="string">""</span><span>,&nbsp;array1));&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;exif_array.push_back(std::make_pair(<span class="string">""</span><span>,&nbsp;array2));&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;exif_array.push_back(std::make_pair(<span class="string">""</span><span>,&nbsp;array3));&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span class="comment">//&nbsp;&nbsp;&nbsp;exif_array.push_back(std::make_pair("Make",&nbsp;"NIKON"));</span><span>&nbsp;&nbsp;</span></li><li class="alt"><span class="comment">//&nbsp;&nbsp;&nbsp;exif_array.push_back(std::make_pair("DateTime",&nbsp;"2011:05:31&nbsp;06:47:09"));</span><span>&nbsp;&nbsp;</span></li><li><span class="comment">//&nbsp;&nbsp;&nbsp;exif_array.push_back(std::make_pair("Software",&nbsp;"Ver.1.01"));</span><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;pt.put_child(<span class="string">"exifs"</span><span>,&nbsp;exif_array);&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;std::stringstream&nbsp;s2;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;write_json(s2,&nbsp;pt);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;std::string&nbsp;outstr&nbsp;=&nbsp;s2.str();&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;0;&nbsp;&nbsp;</span></span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">int InsertJson()
{
  std::string str = "{\"code\":0,\"images\":[{\"url\":\"fmn057/20111221/1130/head_kJoO_05d9000251de125c.jpg\"},{\"url\":\"fmn057/20111221/1130/original_kJoO_05d9000251de125c.jpg\"}]}";
  using namespace boost::property_tree;

  std::stringstream ss(str);
  ptree pt;
  try{    
    read_json(ss, pt);
  }
  catch(ptree_error &amp; e) {
    return 1; 
  }

  // 修改/增加一个key-value，key不存在则增加
  pt.put("upid", "00001");

  // 插入一个数组
  ptree exif_array;
  ptree array1, array2, array3;
  array1.put("Make", "NIKON");
  array2.put("DateTime", "2011:05:31 06:47:09");
  array3.put("Software", "Ver.1.01");
  exif_array.push_back(std::make_pair("", array1));
  exif_array.push_back(std::make_pair("", array2));
  exif_array.push_back(std::make_pair("", array3));

//   exif_array.push_back(std::make_pair("Make", "NIKON"));
//   exif_array.push_back(std::make_pair("DateTime", "2011:05:31 06:47:09"));
//   exif_array.push_back(std::make_pair("Software", "Ver.1.01"));

  pt.put_child("exifs", exif_array);
  std::stringstream s2;
  write_json(s2, pt);
  std::string outstr = s2.str();

  return 0;
}</pre>
<p>&nbsp;</p>
<h3><a name="t2"></a>三. 两种解析库的使用经验</h3>
<p>1. 用boost::property_tree解析字符串遇到"\/"时解析失败，而jsoncpp可以解析成功，要知道'/'前面加一个'\'是JSON标准格式。</p>
<p>2. boost::property_tree的read_json和write_json在多线程中使用会引起崩溃。</p>
<p>针对1，可以在使用boost::property_tree解析前写个函数去掉"\/"中的'\'，针对2，在多线程中同步一下可以解决。</p>
<p>我的使用心得：使用boost::property_tree不仅可以解析json，还可以解析xml，info等格式的数据。对于解析json，使用boost::property_tree解析还可以忍受，但解析xml，由于遇到问题太多只能换其它库了。</p><img src ="http://www.cppblog.com/niewenlong/aggbug/198718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2013-03-22 13:53 <a href="http://www.cppblog.com/niewenlong/archive/2013/03/22/198718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CString 常用操作种种</title><link>http://www.cppblog.com/niewenlong/archive/2013/03/18/198561.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 18 Mar 2013 13:58:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2013/03/18/198561.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/198561.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2013/03/18/198561.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/198561.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/198561.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: //A.构造函数，CStringT提供了19个构造函数，其中一个旨在.NET平台托管C++工程中才被编译，我只写几个我觉得常用的&nbsp;&nbsp;//1.默认构造函数，生成一个""字符串&nbsp;&nbsp;CString&nbsp;cstr1;&nbsp;&nbsp;//2.拷贝构造函数&nbsp;&nbsp;CString&nbsp;cstr2(cstr1);&nbsp;&nbsp;/...&nbsp;&nbsp;<a href='http://www.cppblog.com/niewenlong/archive/2013/03/18/198561.html'>阅读全文</a><img src ="http://www.cppblog.com/niewenlong/aggbug/198561.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2013-03-18 21:58 <a href="http://www.cppblog.com/niewenlong/archive/2013/03/18/198561.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL 文本导入 方式 bcp OpenRowset  opendatasource BULK INSERT </title><link>http://www.cppblog.com/niewenlong/archive/2013/03/18/198558.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 18 Mar 2013 13:11:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2013/03/18/198558.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/198558.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2013/03/18/198558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/198558.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/198558.html</trackback:ping><description><![CDATA[<div>select * from OpenRowset('MSDASQL', 'Driver={Microsoft Text Driver (*.txt; *.csv)};DefaultDir=C:\Users\Administrator\Desktop;','select * from Num.txt')&nbsp;</div><div></div><div>select * from opendatasource('MICROSOFT.JET.OLEDB.4.0','Text;DATABASE=C:\Users\Administrator\Desktop')...[Num.txt]</div><div></div><div>BULK INSERT master..Temp FROM 'C:\Users\Administrator\Desktop\Num.txt' WITH &nbsp;( FIELDTERMINATOR ='<span style="white-space:pre">	</span>', ROWTERMINATOR= '\n')&nbsp;<br /><br /><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;">/** 导入文本文件</span><br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" /><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;">EXEC master..xp_cmdshell 'bcp dbname..tablename in c:\DT.txt -c -Sservername -Usa -Ppassword'</span><br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" />&nbsp;<br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" /><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;">/** 导出文本文件</span><br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" /><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;">EXEC master..xp_cmdshell 'bcp dbname..tablename out c:\DT.txt -c -Sservername -Usa -Ppassword'</span><br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" /><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;">或</span><br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" /><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;">EXEC master..xp_cmdshell 'bcp "Select * from dbname..tablename" queryout c:\DT.txt -c -Sservername -Usa -Ppassword'</span><br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" />&nbsp;<br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" /><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;">导出到TXT文本，用逗号分开</span><br style="margin: 0px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;" /><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;">exec master..xp_cmdshell 'bcp "库名..表名" out "d:\tt.txt" -c -t ,-U sa -P password'<br /><br /></span><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">在做一些web数据库管理系统的时候经常要实现将帐户批量注册的功能，今天就来讲讲如何在C#-web项目中将txt文件和excel文件导入SQL2000数据库。</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">1.数据库准备</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">在SQL2000数据库的实例数据库pubs中建立一个数据表txtInsert，字段很简单：id，name两个。</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">2.txt文本文件导入</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">对于数据文件导入与导出SQL2000提供了BULK INSERT和BCP语句，在这里可以使用BULK INSERT命令实现。假设在c盘上有一个文本文件stu.txt内容为：</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 1,tom</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 2,jack</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 3,jhon</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; ......</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">实现导入的C#代码如下：</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">protected System.Web.UI.HtmlControls.HtmlInputFile fName;&nbsp;&nbsp;</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">protected System.Web.UI.WebControls.Button BtnInsert;</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">//上面两个控件自己添加</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><div style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 1314.171875px; word-break: break-all; background-color: #eeeeee;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" /><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;BtnInsert_Click(</span><span style="color: #0000ff;">object</span><span style="color: #000000;">&nbsp;sender,&nbsp;System.EventArgs&nbsp;e)<br /><img id="Codehighlighter1_66_1032_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;</span><span id="Codehighlighter1_66_1032_Open_Text"><span style="color: #000000;">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;fPath</span><span style="color: #000000;">=</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.fName.PostedFile.FileName;</span><span style="color: #008000;">//</span><span style="color: #008000;">获得要导入的文本文件&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;extName</span><span style="color: #000000;">=</span><span style="color: #000000;">fPath.Substring(fPath.LastIndexOf(</span><span style="color: #000000;">"</span><span style="color: #000000;">.</span><span style="color: #000000;">"</span><span style="color: #000000;">)</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">);</span><span style="color: #008000;">//</span><span style="color: #008000;">获得文件的扩展名&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SqlConnection&nbsp;con</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SqlConnection(</span><span style="color: #000000;">"</span><span style="color: #000000;">server=.;database=pubs;uid=sa;pwd=;</span><span style="color: #000000;">"</span><span style="color: #000000;">);</span><span style="color: #008000;">//</span><span style="color: #008000;">数据库连接对象</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;con.Open();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br /><img id="Codehighlighter1_394_871_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_394_871_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SqlCommand&nbsp;com</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SqlCommand(</span><span style="color: #000000;">"</span><span style="color: #000000;">BULK&nbsp;INSERT&nbsp;pubs.dbo.txtInsert&nbsp;FROM&nbsp;'</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">fPath</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">'&nbsp;WITH&nbsp;&nbsp;(FIELDTERMINATOR&nbsp;=&nbsp;',',ROWTERMINATOR=&nbsp;'\n')</span><span style="color: #000000;">"</span><span style="color: #000000;">,con);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">其中的FIELDTERMINATOR=','指明字段间所使用的分隔符为逗号<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">其中ROWTERMINATOR=&nbsp;'\n'指明记录间所使用的分隔符为回车</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;com.ExecuteNonQuery();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response.Write(</span><span style="color: #000000;">"</span><span style="color: #000000;">&lt;script&nbsp;language=javascript&gt;alert('数据导入成功!')&lt;/script&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(SqlException&nbsp;SQLexc)<br /><img id="Codehighlighter1_930_1017_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_930_1017_Open_Text"><span style="color: #000000;">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response.Write(</span><span style="color: #000000;">"</span><span style="color: #000000;">导入数据库时出错：</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;SQLexc.ToString());<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />con.Close();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" style="border: 0px;"  alt="" />}</span></span></div><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">好了，这个txt文件的导入相对简单，在数据库中我也没有设置主键，我在里面也没有加出错回滚事务操作，在下面的excel文件的导入中介绍。</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">3.excel文件的导入</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">在c盘里建立一个stu.xls文件，在sheet1工作表中有两列数据如下：</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp; 编号&nbsp; 姓名</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tom</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jack</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; john</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp; ......</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">注意，工作表的第一行是作为标题行的不会被插入到数据库中，真正导入从第二行开始。</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">为了演示事物出错回滚，在这里将txtInsert数据库表中的id字段设置为主键。实现的C#代码如下：</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><div style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 1314.171875px; word-break: break-all; background-color: #eeeeee;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" /><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;BtnInsert_Click(</span><span style="color: #0000ff;">object</span><span style="color: #000000;">&nbsp;sender,&nbsp;System.EventArgs&nbsp;e)<br /><img id="Codehighlighter1_66_1275_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;</span><span id="Codehighlighter1_66_1275_Open_Text"><span style="color: #000000;">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;fPath</span><span style="color: #000000;">=</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.fName.PostedFile.FileName;</span><span style="color: #008000;">//</span><span style="color: #008000;">获得要导入的文本文件&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;extName</span><span style="color: #000000;">=</span><span style="color: #000000;">fPath.Substring(fPath.LastIndexOf(</span><span style="color: #000000;">"</span><span style="color: #000000;">.</span><span style="color: #000000;">"</span><span style="color: #000000;">)</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">);</span><span style="color: #008000;">//</span><span style="color: #008000;">获得文件的扩展名&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;SqlConnection&nbsp;con</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SqlConnection(</span><span style="color: #000000;">"</span><span style="color: #000000;">server=.;database=pubs;uid=sa;pwd=;</span><span style="color: #000000;">"</span><span style="color: #000000;">);</span><span style="color: #008000;">//</span><span style="color: #008000;">数据库连接对象</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;con.Open();&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">注意下面的连接字符串，是它起到了导入的作用</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;SqlCommand&nbsp;excelCmd</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SqlCommand(</span><span style="color: #000000;">"</span><span style="color: #000000;">insert&nbsp;into&nbsp;txtInsert&nbsp;select&nbsp;*&nbsp;from&nbsp;OPENROWSET('MICROSOFT.JET.OLEDB.4.0','Excel&nbsp;5.0;HDR=YES;DATABASE=</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">fPath</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">',Sheet1$)</span><span style="color: #000000;">"</span><span style="color: #000000;">,con);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;SqlTransaction&nbsp;myTran</span><span style="color: #000000;">=</span><span style="color: #000000;">con.BeginTransaction();</span><span style="color: #008000;">//</span><span style="color: #008000;">开始一个事务操作</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;excelCmd.Transaction</span><span style="color: #000000;">=</span><span style="color: #000000;">myTran;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br /><img id="Codehighlighter1_614_773_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_614_773_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;excelCmd.ExecuteNonQuery();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myTran.Commit();</span><span style="color: #008000;">//</span><span style="color: #008000;">提交事务&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response.Write(</span><span style="color: #000000;">"</span><span style="color: #000000;">&lt;script&nbsp;language=javascript&gt;alert('数据导入成功!')&lt;/script&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(SqlException&nbsp;err)<br /><img id="Codehighlighter1_808_1252_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_808_1252_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myTran.Rollback();&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">出错回滚事务操作<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">以下三行是去掉数据库出错信息中的非法字符单引号、回车和换行符，否则在使用时javascript代码将有语法错误<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">因为js的编码和c#的编码不同</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;errString</span><span style="color: #000000;">=</span><span style="color: #000000;">err.Message.Replace(</span><span style="color: #000000;">"</span><span style="color: #000000;">'</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errString</span><span style="color: #000000;">=</span><span style="color: #000000;">errString.Replace(Convert.ToChar(</span><span style="color: #000000;">13</span><span style="color: #000000;">).ToString(),</span><span style="color: #000000;">""</span><span style="color: #000000;">);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errString</span><span style="color: #000000;">=</span><span style="color: #000000;">errString.Replace(Convert.ToChar(</span><span style="color: #000000;">10</span><span style="color: #000000;">).ToString(),</span><span style="color: #000000;">""</span><span style="color: #000000;">);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">显示出错信息框</span><span style="color: #008000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response.Write(</span><span style="color: #000000;">"</span><span style="color: #000000;">&lt;script&nbsp;language=javascript&gt;alert('导入数据库时出错!详细信息:</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">errString</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">')&lt;/script&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;con.Close();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;}</span></span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" /></span></div><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">这里&#8220;显示出错信息框&#8221;开始我没有田间那三行代码，结果搞了半天，最后还是在html文件中发现javascript代码部分出现了分行，老是提示&#8220;未结束的字符串常量&#8221;，所以导致不能打开信息框，郁闷死我了，花了好多时间。</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">4.将excel中部分列导入数据库的方法</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">上面讲了关于将整个excel文件导入数据库的方法，那么在实际项目中遇到将excel文件中若干列导入数据库怎么办的呢，原理差不多，我就将代码直接给出了：</span><br style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><div style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 1314.171875px; word-break: break-all; background-color: #eeeeee;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">string</font><span style="color: #000000;">&nbsp;</span>&nbsp;fPath=this.fName.PostedFile.FileName;//获得要导入的文本文件&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">string</font><span style="color: #000000;">&nbsp;</span>&nbsp;extName=fPath.Substring(fPath.LastIndexOf(".")+1);//获得文件的扩展名&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlConnection con=new SqlConnection("server=.;database=pubs;uid=sa;pwd=;");//数据库连接对象<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; con.Open();<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" /><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /></span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string</span><span style="color: #000000;">&nbsp;mystring</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">Provider&nbsp;=&nbsp;Microsoft.Jet.OLEDB.4.0&nbsp;;&nbsp;Data&nbsp;Source&nbsp;=&nbsp;'</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">fPath</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">';Extended&nbsp;Properties=Excel&nbsp;8.0</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OleDbConnection&nbsp;cnnxls&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;OleDbConnection&nbsp;(mystring);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OleDbDataAdapter&nbsp;myDa&nbsp;</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;OleDbDataAdapter(</span><span style="color: #000000;">"</span><span style="color: #000000;">select&nbsp;*&nbsp;from&nbsp;[Sheet1$]</span><span style="color: #000000;">"</span><span style="color: #000000;">,cnnxls);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DataSet&nbsp;myDs&nbsp;</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;DataSet();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myDa.Fill(myDs);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(myDs.Tables[</span><span style="color: #000000;">0</span><span style="color: #000000;">].Rows.Count&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br /><img id="Codehighlighter1_356_1330_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_356_1330_Open_Text"><span style="color: #000000;">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;strSql&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">""</span><span style="color: #000000;">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">string</span><span style="color: #000000;">&nbsp;CnnString</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">Provider=SQLOLEDB;database=pubs;server=.;uid=sa;pwd=</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OleDbConnection&nbsp;conn&nbsp;</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;OleDbConnection(CnnString);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn.Open&nbsp;();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OleDbCommand&nbsp;myCmd&nbsp;</span><span style="color: #000000;">=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">myDs.Tables[</span><span style="color: #000000;">0</span><span style="color: #000000;">].Rows.Count;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)</span><span style="color: #008000;">//</span><span style="color: #008000;">第一个工作表中行数，不包括第一行，</span><span style="color: #008000;"><br /><img id="Codehighlighter1_650_1310_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_650_1310_Open_Text"><span style="color: #000000;">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">strSql</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">insert&nbsp;into&nbsp;txtInsert(id,name)&nbsp;values&nbsp;(</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strSql&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;myDs.Tables[</span><span style="color: #000000;">0</span><span style="color: #000000;">].Rows[i].ItemArray[</span><span style="color: #000000;">0</span><span style="color: #000000;">].ToString()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;'</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strSql&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;myDs.Tables[</span><span style="color: #000000;">0</span><span style="color: #000000;">].Rows[i].ItemArray[</span><span style="color: #000000;">1</span><span style="color: #000000;">].ToString()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">')</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myCmd</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;OleDbCommand(strSql,conn);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" /></span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br /><img id="Codehighlighter1_997_1155_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_997_1155_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myCmd.ExecuteNonQuery();<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response.Write(</span><span style="color: #000000;">"</span><span style="color: #000000;">&lt;script&nbsp;language=javascript&gt;alert('数据导入成功!')&lt;/script&gt;</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(OleDbException&nbsp;err)<br /><img id="Codehighlighter1_1196_1303_Open_Image" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_1196_1303_Open_Text"><span style="color: #000000;">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response.Write(</span><span style="color: #000000;">"</span><span style="color: #000000;">导入数据库时出错：</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">err.ToString());<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000;"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top" style="border: 0px;"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn.Close();</span></span></div><span style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">其他部分代码自己加吧，这里就是出错失误回滚有点不好处理，请高手指教！！</span><span style="color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><br /></span></div><img src ="http://www.cppblog.com/niewenlong/aggbug/198558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2013-03-18 21:11 <a href="http://www.cppblog.com/niewenlong/archive/2013/03/18/198558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC控件ListCtrl的使用方法总汇 </title><link>http://www.cppblog.com/niewenlong/archive/2013/03/18/198546.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 18 Mar 2013 07:19:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2013/03/18/198546.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/198546.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2013/03/18/198546.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/198546.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/198546.html</trackback:ping><description><![CDATA[<p>以下未经说明，<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>默认<span style="line-height: 1.3em">view </span><wbr><wbr><wbr><wbr>风格为<span style="line-height: 1.3em">report</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">-------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">1. CListCtrl </span><wbr><wbr><wbr><wbr>风格 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVS_ICON: </span><wbr><wbr><wbr><wbr>为每个<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr>显示大图标 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVS_SMALLICON: </span><wbr><wbr><wbr><wbr>为每个<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr>显示小图标 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVS_LIST: </span><wbr><wbr><wbr><wbr>显示一列带有小图标的<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVS_REPORT: </span><wbr><wbr><wbr><wbr>显示<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr>详细资料 <br />直观的理解：<span style="line-height: 1.3em">windows</span><wbr><wbr><wbr><wbr>资源管理器，<span style="line-height: 1.3em">"</span><wbr><wbr><wbr><wbr>查看<span style="line-height: 1.3em">"</span><wbr><wbr><wbr><wbr>标签下的<span style="line-height: 1.3em">"</span><wbr><wbr><wbr><wbr>大图标，小图标，列表，详细资料 <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">2. </span><wbr><wbr><wbr><wbr>设置<span style="line-height: 1.3em">listctrl </span><wbr><wbr><wbr><wbr>风格及扩展风格 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LONG lStyle;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lStyle = GetWindowLong(m_list.m_hWnd, GWL_STYLE);//</span><wbr><wbr><wbr><wbr>获取当前窗口<span style="line-height: 1.3em">style</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lStyle &amp;= ~LVS_TYPEMASK; //</span><wbr><wbr><wbr><wbr>清除显示方式位 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lStyle |= LVS_REPORT; //</span><wbr><wbr><wbr><wbr>设置<span style="line-height: 1.3em">style</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);//</span><wbr><wbr><wbr><wbr>设置<span style="line-height: 1.3em">style</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwStyle = m_list.GetExtendedStyle();</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwStyle |= LVS_EX_FULLROWSELECT;//</span><wbr><wbr><wbr><wbr>选中某行使整行高亮（只适用与<span style="line-height: 1.3em">report</span><wbr><wbr><wbr><wbr>风格的<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>） <br /><span style="line-height: 1.3em">dwStyle |= LVS_EX_GRIDLINES;//</span><wbr><wbr><wbr><wbr>网格线（只适用与<span style="line-height: 1.3em">report</span><wbr><wbr><wbr><wbr>风格的<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>） <br /><span style="line-height: 1.3em">dwStyle |= LVS_EX_CHECKBOXES;//item</span><wbr><wbr><wbr><wbr>前生成<span style="line-height: 1.3em">checkbox</span><wbr><wbr><wbr><wbr>控件 <br /><span style="line-height: 1.3em">m_list.SetExtendedStyle(dwStyle); //</span><wbr><wbr><wbr><wbr>设置扩展风格 <br />注：<span style="line-height: 1.3em">listview</span><wbr><wbr><wbr><wbr>的<span style="line-height: 1.3em">style</span><wbr><wbr><wbr><wbr>请查阅<span style="line-height: 1.3em">msdn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><wbr><wbr><wbr><wbr> <br /><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceshellui5/html/wce50lrflistviewstyles.asp" target="_blank" link="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceshellui5/html/wce50lrflistviewstyles.asp"><span style="color: rgb(0,0,0); line-height: 1.3em">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceshellui5/html/wce50lrflistviewstyles.asp</span><wbr><wbr><wbr><wbr></a><wbr><wbr><wbr><wbr><span style="color: rgb(0,0,0)"> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">3. </span><wbr><wbr><wbr><wbr>插入数据 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.InsertColumn( 0, "ID", LVCFMT_LEFT, 40 );//</span><wbr><wbr><wbr><wbr>插入列 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.InsertColumn( 1, "NAME", LVCFMT_LEFT, 50 );</span><wbr><wbr><wbr><wbr> </span></p>
<p><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //新插入的在上面<br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nRow = m_list.InsertItem(0, "11");// </span><wbr><wbr><wbr><wbr>插入行<br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.SetItemText(nRow, 1, "jacky");//</span><wbr><wbr><wbr><wbr>设置其它列数据</span></p>
<p><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp; //新插入的数据在下面</span></p>
<p><span style="color: rgb(0,0,0)">&nbsp;&nbsp; int nIndex = m_list.GetItemCount();<br />&nbsp;&nbsp;&nbsp; LV_ITEM lvItem;<br />&nbsp;&nbsp;&nbsp; lvItem.mask = LVIF_TEXT ; <br />&nbsp;&nbsp;&nbsp; lvItem.iItem = nIndex;&nbsp;&nbsp;&nbsp;&nbsp; //行数<br />&nbsp;&nbsp;&nbsp; lvItem.iSubItem = 0;<br />&nbsp;&nbsp;&nbsp; lvItem.pszText = (char*)(LPCTSTR)strCount;&nbsp;&nbsp; //第一列<br />&nbsp;&nbsp;&nbsp; //在最后一行插入记录值.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.InsertItem(&amp;lvItem); <br />&nbsp;&nbsp;&nbsp; //插入其它列<br />&nbsp;&nbsp;&nbsp; m_list.SetItemText(nIndex,1,strLat);</span><span style="color: rgb(0,0,0)"><br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">4. </span><wbr><wbr><wbr><wbr>一直选中<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr> <br />选中<span style="line-height: 1.3em">style</span><wbr><wbr><wbr><wbr>中的<span style="line-height: 1.3em">Show selection always</span><wbr><wbr><wbr><wbr>，或者在上面第<span style="line-height: 1.3em">2</span><wbr><wbr><wbr><wbr>点中设置<span style="line-height: 1.3em">LVS_SHOWSELALWAYS</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">5. </span><wbr><wbr><wbr><wbr>选中和取消选中一行 <br /><span style="line-height: 1.3em">int nIndex = 0;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">//</span><wbr><wbr><wbr><wbr>选中 <br /><span style="line-height: 1.3em">m_list.SetItemState(nIndex, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">//</span><wbr><wbr><wbr><wbr>取消选中 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp; m_list.SetItemState(nIndex, 0, LVIS_SELECTED|LVIS_FOCUSED);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">6. </span><wbr><wbr><wbr><wbr>得到<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>中所有行的<span style="line-height: 1.3em">checkbox</span><wbr><wbr><wbr><wbr>的状态 <br /><span style="line-height: 1.3em">m_list.SetExtendedStyle(LVS_EX_CHECKBOXES);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">CString str;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">for(int i=0; i&lt;m_list.GetItemCount(); i++)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">{</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED || m_list.GetCheck(i))</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">{</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">str.Format(_T("</span><wbr><wbr><wbr><wbr>第<span style="line-height: 1.3em">%d</span><wbr><wbr><wbr><wbr>行的<span style="line-height: 1.3em">checkbox</span><wbr><wbr><wbr><wbr>为选中状态<span style="line-height: 1.3em">"), i);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">AfxMessageBox(str);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">}</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">}</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">7. </span><wbr><wbr><wbr><wbr>得到<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>中所有选中行的序号 <br />方法一： <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CString str;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;m_list.GetItemCount(); i++)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED )</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str.Format(_T("</span><wbr><wbr><wbr><wbr>选中了第<span style="line-height: 1.3em">%d</span><wbr><wbr><wbr><wbr>行<span style="line-height: 1.3em">"), i);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox(str);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br />方法二： <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POSITION pos = m_list.GetFirstSelectedItemPosition();</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pos == NULL)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRACE0("No items were selected!\n");</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Else</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (pos)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nItem = m_list.GetNextSelectedItem(pos);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRACE1("Item %d was selected!\n", nItem);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // you could do your own processing on nItem here</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">8. </span><wbr><wbr><wbr><wbr>得到<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr>的信息 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TCHAR szBuf[1024];</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVITEM lvi;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvi.iItem = nItemIndex;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvi.iSubItem = 0;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvi.mask = LVIF_TEXT;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvi.pszText = szBuf;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvi.cchTextMax = 1024;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.GetItem(&amp;lvi);</span><wbr><wbr><wbr><wbr> <br />关于得到设置<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr>的状态，还可以参考<span style="line-height: 1.3em">msdn</span><wbr><wbr><wbr><wbr>文章 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Q173242: Use Masks to Set/Get Item States in ClistCtrl</span><wbr><wbr><wbr><wbr> <br /></span><a href="http://support.microsoft.com/kb/173242/en-us" target="_blank" link="http://support.microsoft.com/kb/173242/en-us"><span style="color: rgb(0,0,0); line-height: 1.3em">http://support.microsoft.com/kb/173242/en-us</span><wbr><wbr><wbr><wbr></a><wbr><wbr><wbr><wbr><span style="color: rgb(0,0,0)"> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">9. </span><wbr><wbr><wbr><wbr>得到<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>的所有列的<span style="line-height: 1.3em">header</span><wbr><wbr><wbr><wbr>字符串内容 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVCOLUMN lvcol;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp; str[256];</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp; nColNum;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CString&nbsp;&nbsp; strColumnName[4];//</span><wbr><wbr><wbr><wbr>假如有<span style="line-height: 1.3em">4</span><wbr><wbr><wbr><wbr>列 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nColNum = 0;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvcol.mask = LVCF_TEXT;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvcol.pszText = str;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvcol.cchTextMax = 256;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(m_list.GetColumn(nColNum, &amp;lvcol))</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strColumnName[nColNum] = lvcol.pszText;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nColNum++;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">10. </span><wbr><wbr><wbr><wbr>使<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>中一项可见，即滚动滚动条 <br /><span style="line-height: 1.3em">m_list.EnsureVisible(i, FALSE);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">11. </span><wbr><wbr><wbr><wbr>得到<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>列数 <br /><span style="line-height: 1.3em">int nHeadNum = m_list.GetHeaderCtrl()-&gt;GetItemCount();</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">12. </span><wbr><wbr><wbr><wbr>删除所有列 <br />方法一： <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( m_list.DeleteColumn (0))</span><wbr><wbr><wbr><wbr> <br />因为你删除了第一列后，后面的列会依次向上移动。 <br />方法二： <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nColumns = 4;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=nColumns-1; i&gt;=0; i--)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.DeleteColumn (i);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">13. </span><wbr><wbr><wbr><wbr>得到单击的<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>的行列号 <br />添加<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>控件的<span style="line-height: 1.3em">NM_CLICK</span><wbr><wbr><wbr><wbr>消息相应函数 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span><wbr><wbr><wbr><wbr>方法一： <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwPos = GetMessagePos();</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CPoint point( LOWORD(dwPos), HIWORD(dwPos) );</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.ScreenToClient(&amp;point);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVHITTESTINFO lvinfo;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvinfo.pt = point;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvinfo.flags = LVHT_ABOVE;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nItem = m_list.SubItemHitTest(&amp;lvinfo);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(nItem != -1)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CString strtemp;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strtemp.Format("</span><wbr><wbr><wbr><wbr>单击的是第<span style="line-height: 1.3em">%d</span><wbr><wbr><wbr><wbr>行第<span style="line-height: 1.3em">%d</span><wbr><wbr><wbr><wbr>列<span style="line-height: 1.3em">", lvinfo.iItem, lvinfo.iSubItem);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox(strtemp);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span><wbr><wbr><wbr><wbr>方法二<span style="line-height: 1.3em">:</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(pNMListView-&gt;iItem != -1)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CString strtemp;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strtemp.Format("</span><wbr><wbr><wbr><wbr>单击的是第<span style="line-height: 1.3em">%d</span><wbr><wbr><wbr><wbr>行第<span style="line-height: 1.3em">%d</span><wbr><wbr><wbr><wbr>列<span style="line-height: 1.3em">",</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pNMListView-&gt;iItem, pNMListView-&gt;iSubItem);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox(strtemp);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = 0;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">14. </span><wbr><wbr><wbr><wbr>判断是否点击在<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>的<span style="line-height: 1.3em">checkbox</span><wbr><wbr><wbr><wbr>上 <br />添加<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>控件的<span style="line-height: 1.3em">NM_CLICK</span><wbr><wbr><wbr><wbr>消息相应函数 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">DWORD dwPos = GetMessagePos();</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CPoint point( LOWORD(dwPos), HIWORD(dwPos) );&nbsp;&nbsp; </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.ScreenToClient(&amp;point);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVHITTESTINFO lvinfo;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvinfo.pt = point;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lvinfo.flags = LVHT_ABOVE;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UINT nFlag;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nItem = m_list.HitTest(point, &amp;nFlag);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span><wbr><wbr><wbr><wbr>判断是否点在<span style="line-height: 1.3em">checkbox</span><wbr><wbr><wbr><wbr>上 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(nFlag == LVHT_ONITEMSTATEICON)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox("</span><wbr><wbr><wbr><wbr>点在<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>的<span style="line-height: 1.3em">checkbox</span><wbr><wbr><wbr><wbr>上<span style="line-height: 1.3em">");</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = 0;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">15. </span><wbr><wbr><wbr><wbr>右键点击<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>的<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr>弹出菜单 <br />添加<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>控件的<span style="line-height: 1.3em">NM_RCLICK</span><wbr><wbr><wbr><wbr>消息相应函数 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void CTest6Dlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(pNMListView-&gt;iItem != -1)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwPos = GetMessagePos();</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CPoint point( LOWORD(dwPos), HIWORD(dwPos) );</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CMenu menu;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VERIFY( menu.LoadMenu( IDR_MENU1 ) );</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CMenu* popup = menu.GetSubMenu(0);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT( popup != NULL ); </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; popup-&gt;TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this );</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = 0;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp; }</span></span></p>
<div>16. item<wbr><wbr><wbr><wbr>切换焦点时<span style="line-height: 1.3em">(</span><wbr><wbr><wbr><wbr>包括用键盘和鼠标切换<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr>时<span style="line-height: 1.3em">)</span><wbr><wbr><wbr><wbr>，状态的一些变化顺序 <br />添加<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>控件的<span style="line-height: 1.3em">LVN_ITEMCHANGED</span><wbr><wbr><wbr><wbr>消息相应函数 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void CTest6Dlg::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO: Add your control notification handler code here</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CString sTemp;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((pNMListView-&gt;uOldState &amp; LVIS_FOCUSED) == LVIS_FOCUSED &amp;&amp; (pNMListView-&gt;uNewState &amp; LVIS_FOCUSED) == 0)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sTemp.Format("%d losted focus",pNMListView-&gt;iItem);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if((pNMListView-&gt;uOldState &amp; LVIS_FOCUSED) == 0 &amp;&amp;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (pNMListView-&gt;uNewState &amp; LVIS_FOCUSED) == LVIS_FOCUSED)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sTemp.Format("%d got focus",pNMListView-&gt;iItem);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((pNMListView-&gt;uOldState &amp; LVIS_SELECTED) == LVIS_SELECTED &amp;&amp;</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (pNMListView-&gt;uNewState &amp; LVIS_SELECTED) == 0)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sTemp.Format("%d losted selected",pNMListView-&gt;iItem);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">else if((pNMListView-&gt;uOldState &amp; LVIS_SELECTED) == 0 &amp;&amp; (pNMListView-&gt;uNewState &amp; LVIS_SELECTED) == LVIS_SELECTED)</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">sTemp.Format("%d got selected",pNMListView-&gt;iItem);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">}</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">*pResult = 0; </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">17. </span><wbr><wbr><wbr><wbr>得到另一个进程里的<span style="line-height: 1.3em">listctrl</span><wbr><wbr><wbr><wbr>控件的<span style="line-height: 1.3em">item</span><wbr><wbr><wbr><wbr>内容 <br /><a href="http://www.codeproject.com/threads/int64_memsteal.asp" target="_blank" link="http://www.codeproject.com/threads/int64_memsteal.asp"><span style="color: rgb(0,0,0); line-height: 1.3em">http://www.codeproject.com/threads/int64_memsteal.asp</span><wbr><wbr><wbr><wbr></a><wbr><wbr><wbr><wbr><span style="color: rgb(0,0,0)"> <br /><br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">18. </span><wbr><wbr><wbr><wbr>选中<span style="line-height: 1.3em">listview</span><wbr><wbr><wbr><wbr>中的<span style="line-height: 1.3em">item </span><wbr><wbr><wbr><wbr><br /><span style="line-height: 1.3em">Q131284: How To Select a Listview Item Programmatically</span><wbr><wbr><wbr><wbr> <br /></span><a href="http://support.microsoft.com/kb/131284/en-us" target="_blank" link="http://support.microsoft.com/kb/131284/en-us"><span style="color: rgb(0,0,0); line-height: 1.3em">http://support.microsoft.com/kb/131284/en-us</span><wbr><wbr><wbr><wbr></a><wbr><wbr><wbr><wbr><span style="color: rgb(0,0,0)"> <br /><br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">19. </span><wbr><wbr><wbr><wbr>如何在<span style="line-height: 1.3em">CListView</span><wbr><wbr><wbr><wbr>中使用<span style="line-height: 1.3em">CListCtrl</span><wbr><wbr><wbr><wbr>的派生类 <br /></span><a href="http://www.codeguru.com/cpp/controls/listview/introduction/article.php/c919/" target="_blank" link="http://www.codeguru.com/cpp/controls/listview/introduction/article.php/c919/"><span style="color: rgb(0,0,0); line-height: 1.3em">http://www.codeguru.com/cpp/controls/listview/introduction/article.php/c919/</span><wbr><wbr><wbr><wbr></a><wbr><wbr><wbr><wbr><span style="color: rgb(0,0,0)"> <br /><br /><span style="line-height: 1.3em">--------------------------------------------------------------------------------</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">20. listctrl</span><wbr><wbr><wbr><wbr>的<span style="line-height: 1.3em">subitem</span><wbr><wbr><wbr><wbr>添加图标 <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.SetExtendedStyle(LVS_EX_SUBITEMIMAGES);</span><wbr><wbr><wbr><wbr> <br /><span style="line-height: 1.3em">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.SetItem(..); //</span><wbr><wbr><wbr><wbr>具体参数请参考<span style="line-height: 1.3em">msdn</span><wbr><wbr><wbr><wbr> </span></div><img src ="http://www.cppblog.com/niewenlong/aggbug/198546.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2013-03-18 15:19 <a href="http://www.cppblog.com/niewenlong/archive/2013/03/18/198546.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用ICMP和RAS（Remote Access Service）进行的一些网络操作</title><link>http://www.cppblog.com/niewenlong/archive/2013/03/17/198515.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Sun, 17 Mar 2013 12:10:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2013/03/17/198515.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/198515.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2013/03/17/198515.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/198515.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/198515.html</trackback:ping><description><![CDATA[首先是用ICMP检查网络是否连通：<br /><br />
<div style="font-size: 13px; border-top: rgb(204,204,204) 1px solid; border-right: rgb(204,204,204) 1px solid; border-bottom: rgb(204,204,204) 1px solid; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: rgb(204,204,204) 1px solid; padding-right: 5px; width: 98%; background-color: rgb(238,238,238)"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: rgb(0,0,255)">bool</span><span style="color: rgb(0,0,0)">&nbsp;Util::CheckInternet()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">char</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">*</span><span style="color: rgb(0,0,0)">SendData&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">Data&nbsp;Buffer</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;LPVOID&nbsp;ReplyBuffer;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwRetVal;<br />&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hIcmpFile;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">bool</span><span style="color: rgb(0,0,0)">&nbsp;b</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,255)">false</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">&nbsp;((hIcmpFile&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;IcmpCreateFile())&nbsp;</span><span style="color: rgb(0,0,0)">==</span><span style="color: rgb(0,0,0)">&nbsp;INVALID_HANDLE_VALUE)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">false</span><span style="color: rgb(0,0,0)">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;ReplyBuffer&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;(VOID</span><span style="color: rgb(0,0,0)">*</span><span style="color: rgb(0,0,0)">)&nbsp;malloc(</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(ICMP_ECHO_REPLY)&nbsp;</span><span style="color: rgb(0,0,0)">+</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(SendData));<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">&nbsp;((dwRetVal&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;IcmpSendEcho(hIcmpFile,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inet_addr(</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">209.131.36.158</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">), //用的雅虎的一个IP，可能延迟会大一点，用国内的会小一点<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SendData,&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(SendData),&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,&nbsp;ReplyBuffer,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(ReplyBuffer)&nbsp;</span><span style="color: rgb(0,0,0)">+</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(ICMP_ECHO_REPLY),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">1000</span><span style="color: rgb(0,0,0)">))&nbsp;</span><span style="color: rgb(0,0,0)">!=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,255)">true</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;free(ReplyBuffer);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;b;<br />}</span></div>很简单的几行代码，没有注释；<br />如果网络不通的话枚举拨号连接，进行拨号：<br />
<div style="font-size: 13px; border-top: rgb(204,204,204) 1px solid; border-right: rgb(204,204,204) 1px solid; border-bottom: rgb(204,204,204) 1px solid; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: rgb(204,204,204) 1px solid; padding-right: 5px; width: 98%; background-color: rgb(238,238,238)"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: rgb(0,0,255)">bool</span><span style="color: rgb(0,0,0)">&nbsp;RASManager::ConnectNetwork()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;RASENTRYNAME&nbsp;Entries[</span><span style="color: rgb(0,0,0)">15</span><span style="color: rgb(0,0,0)">];&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;cb,cEntries,dwRet;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;Entries[</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">].dwSize</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASENTRYNAME);&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;cb</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(Entries);&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;cEntries</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;dwRet</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">::RasEnumEntries(NULL,&nbsp;NULL,&nbsp;</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">Entries[</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">],&nbsp;</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">cb,&nbsp;</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">cEntries);</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">如果函数成功，则返回0&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,128,0)"><br /></span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">(dwRet&nbsp;</span><span style="color: rgb(0,0,0)">==</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">)&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CHAR&nbsp;&nbsp;szRasEntryName[RAS_MaxEntryName&nbsp;</span><span style="color: rgb(0,0,0)">+</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">1</span><span style="color: rgb(0,0,0)">]</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">{</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">for</span><span style="color: rgb(0,0,0)">(UINT&nbsp;i</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;i</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">cEntries;i</span><span style="color: rgb(0,0,0)">++</span><span style="color: rgb(0,0,0)">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(szRasEntryName,Entries[i].szEntryName);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RASDIALPARAMS&nbsp;rdParams;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwRet;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hConn</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">NULL;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rdParams.dwSize</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASDIALPARAMS);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(rdParams.szEntryName,szRasEntryName);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(rdParams.szPhoneNumber,</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">#777</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">);</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">我用的3G卡，拨#777号码</span><span style="color: rgb(0,128,0)"><br /></span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(rdParams.szUserName,</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">用户名</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(rdParams.szPassword,</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">密码</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(rdParams.szDomain,"");//这个也很重要，指定域，如果不指定这个的话下面注释的两句一定要加上，下边两句的意思是获取最后一次连接成功时的参数信息，如果用下边两句的话连同这行和这行上面的三行都可以省略<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // BOOL&nbsp;fPass;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //RasGetEntryDialParams(NULL,&nbsp;</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">rdParams,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">fPass);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwRet</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">RasDial(NULL,NULL,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">rdParams,</span><span style="color: rgb(0,0,0)">0L</span><span style="color: rgb(0,0,0)">,NULL,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">hConn);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">(dwRet</span><span style="color: rgb(0,0,0)">!=</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">false</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">true</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">false</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /></span></div>预先建立拨号连接，以上拨号代码经过修改已经不需要保存密码，只建立一个拨号连接即可。<strong>Windows&nbsp;XP or later:&nbsp;&nbsp;</strong>Do not use the <strong>RasSetEntryDialParams</strong> function. MSDN上面的说法就是<strong>RasSetEntryDialParams</strong> 别在XP之后的系统上使用了。<br />检查拨号连接的状态，如果已经通过拨号连接上了网络当然不用再进行拨号了，代码如下：<br />
<div style="font-size: 13px; border-top: rgb(204,204,204) 1px solid; border-right: rgb(204,204,204) 1px solid; border-bottom: rgb(204,204,204) 1px solid; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: rgb(204,204,204) 1px solid; padding-right: 5px; width: 98%; background-color: rgb(238,238,238)"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: rgb(0,0,255)">bool</span><span style="color: rgb(0,0,0)">&nbsp;RASManager::RasGetConnectStatus()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;LPRASCONN&nbsp;lpRasConn&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;NULL;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;cbBuf&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;cConn&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;dwRet&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;HRASCONN&nbsp;&nbsp;hrasconn;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">bool</span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;bResult</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">FALSE;<br />&nbsp;&nbsp;&nbsp;&nbsp;RASCONNSTATUS&nbsp;rasStatus;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;UINT&nbsp;&nbsp;&nbsp;ndx;<br />&nbsp;&nbsp;&nbsp;&nbsp;cbBuf&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASCONN);<br />&nbsp;&nbsp;&nbsp;&nbsp;lpRasConn&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;(LPRASCONN)malloc((UINT)cbBuf);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">&nbsp;(lpRasConn&nbsp;</span><span style="color: rgb(0,0,0)">!=</span><span style="color: rgb(0,0,0)">&nbsp;NULL)<br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpRasConn</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">dwSize&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASCONN);&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwRet&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;RasEnumConnections(lpRasConn,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">cbBuf,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">cConn);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">for</span><span style="color: rgb(0,0,0)">(ndx</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;ndx</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">cConn;ndx</span><span style="color: rgb(0,0,0)">++</span><span style="color: rgb(0,0,0)">)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hrasconn&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;lpRasConn[ndx].hrasconn;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rasStatus.dwSize&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASCONNSTATUS);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwRet&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;::RasGetConnectStatus(hrasconn,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">rasStatus);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">(dwRet)&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bResult</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">FALSE;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">(rasStatus.rasconnstate&nbsp;</span><span style="color: rgb(0,0,0)">==</span><span style="color: rgb(0,0,0)">&nbsp;RASCS_Connected)&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bResult</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">TRUE;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bResult</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">FALSE;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bResult</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">FALSE;<br />&nbsp;&nbsp;&nbsp;&nbsp;free(lpRasConn);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;bResult;<br />}</span></div>以上判断是如果检查到有一个已经连接的拨号连接就返回了，应该不会有两个或者以上的拨号连接同时连接，打开端口会失败的。<br />还有一个是断线：<br />
<div style="font-size: 13px; border-top: rgb(204,204,204) 1px solid; border-right: rgb(204,204,204) 1px solid; border-bottom: rgb(204,204,204) 1px solid; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: rgb(204,204,204) 1px solid; padding-right: 5px; width: 98%; background-color: rgb(238,238,238)"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: rgb(0,0,255)">void</span><span style="color: rgb(0,0,0)">&nbsp;RASManager::HungUP()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;LPRASCONN&nbsp;lpRasConn</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">NULL;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;cbBuf&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;cConn&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;dwRet&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;HRASCONN&nbsp;&nbsp;&nbsp;hrasconn;<br />&nbsp;&nbsp;&nbsp;&nbsp;RASCONNSTATUS&nbsp;rasStatus;<br />&nbsp;&nbsp;&nbsp;&nbsp;UINT&nbsp;&nbsp;&nbsp;ndx;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;cbBuf&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASCONN);<br />&nbsp;&nbsp;&nbsp;&nbsp;lpRasConn&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;(LPRASCONN)malloc((UINT)cbBuf);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">(lpRasConn&nbsp;</span><span style="color: rgb(0,0,0)">!=</span><span style="color: rgb(0,0,0)">&nbsp;NULL)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpRasConn</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">dwSize&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASCONN);&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwRet&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;RasEnumConnections(lpRasConn,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">cbBuf,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">cConn);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">for</span><span style="color: rgb(0,0,0)">(ndx</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;ndx</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">cConn;ndx</span><span style="color: rgb(0,0,0)">++</span><span style="color: rgb(0,0,0)">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hrasconn&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;lpRasConn[ndx].hrasconn;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rasStatus.dwSize&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASCONNSTATUS);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwRet&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;::RasGetConnectStatus(hrasconn,</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">rasStatus);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">(</span><span style="color: rgb(0,0,0)">!</span><span style="color: rgb(0,0,0)">dwRet)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">(rasStatus.rasconnstate&nbsp;</span><span style="color: rgb(0,0,0)">==</span><span style="color: rgb(0,0,0)">&nbsp;RASCS_Connected)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RasHangUp(hrasconn);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(lpRasConn);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div>这个没什么好说的，执行关闭拨号连接的操作。<br />用程序创建连接，经过修改，已经可以正常创建连接，代码如下：<br />
<div style="font-size: 13px; border-top: rgb(204,204,204) 1px solid; border-right: rgb(204,204,204) 1px solid; border-bottom: rgb(204,204,204) 1px solid; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: rgb(204,204,204) 1px solid; padding-right: 5px; width: 98%; background-color: rgb(238,238,238)"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: rgb(0,0,255)">bool</span><span style="color: rgb(0,0,0)">&nbsp;RASManager::CreateRASLink()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;LPRASENTRY&nbsp;lpRasEntry&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;NULL;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;cb&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASENTRY);<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwBufferSize&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwRet&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">&nbsp;取得entry的大小,这句也不知道是不是必须的,因为sizeof(RASENTRY)和这里取到的dwBufferSize是一样的,不过还是Get一下安全点</span><span style="color: rgb(0,128,0)"><br /></span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;RasGetEntryProperties(NULL,</span><span style="color: rgb(0,0,0)">""</span><span style="color: rgb(0,0,0)">,&nbsp;NULL,&nbsp;</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">dwBufferSize,&nbsp;NULL,&nbsp;NULL);&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">&nbsp;(dwBufferSize&nbsp;</span><span style="color: rgb(0,0,0)">==</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">false</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;lpRasEntry&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;(LPRASENTRY)HeapAlloc(GetProcessHeap(),&nbsp;HEAP_ZERO_MEMORY,&nbsp;dwBufferSize);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">&nbsp;(lpRasEntry&nbsp;</span><span style="color: rgb(0,0,0)">==</span><span style="color: rgb(0,0,0)">&nbsp;NULL)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">false</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;ZeroMemory(lpRasEntry,&nbsp;</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASENTRY));<br />&nbsp;&nbsp;&nbsp;&nbsp;lpRasEntry</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">dwSize&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;dwBufferSize;<br />&nbsp;&nbsp;&nbsp;&nbsp;lpRasEntry</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">dwfOptions&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;RASEO_RemoteDefaultGateway|RASEO_PreviewPhoneNumber|RASEO_PreviewUserPw;&nbsp;</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)"> 这里的几个选项挺重要的，</span><span style="color: rgb(0,0,0)">RASEO_RemoteDefaultGateway这个选项把创建的连接设置为默认连接，</span><span style="color: rgb(0,0,0)">RASEO_PreviewPhoneNumber</span>对应选项中的提示输入电话号码，<span style="color: rgb(0,0,0)">RASEO_PreviewUserPw对应选项中的提示用户名和密码</span><br /><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;lpRasEntry</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">dwType&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;RASET_Phone;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;lstrcpy(lpRasEntry</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">szDeviceType,&nbsp;RASDT_Modem);<br />&nbsp;&nbsp;&nbsp;&nbsp;lstrcpy(lpRasEntry</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">szDeviceName,</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">www</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">);<br />&nbsp;&nbsp;&nbsp;&nbsp;lpRasEntry</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">dwfNetProtocols&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;RASNP_Ip;<br />&nbsp;&nbsp;&nbsp;&nbsp;lpRasEntry</span><span style="color: rgb(0,0,0)">-&gt;</span><span style="color: rgb(0,0,0)">dwFramingProtocol&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;RASFP_Ppp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;dwRet&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;RasSetEntryProperties(NULL,&nbsp;</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">www</span><span style="color: rgb(0,0,0)">"</span><span style="color: rgb(0,0,0)">,&nbsp;lpRasEntry,&nbsp;dwBufferSize,&nbsp;NULL,&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">);&nbsp;</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">&nbsp;创建连接</span><span style="color: rgb(0,128,0)"><br />//</span>The <strong>RasSetEntryProperties</strong> function changes the connection information for an entry in the phone book or creates a new phone-book entry.（reference MSDN）<br /><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;HeapFree(GetProcessHeap(),&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">,&nbsp;(LPVOID)lpRasEntry);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">&nbsp;(dwRet&nbsp;</span><span style="color: rgb(0,0,0)">!=</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">false</span><span style="color: rgb(0,0,0)">;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">true</span><span style="color: rgb(0,0,0)">;<br />}</span></div>上面的代码到是可以创建一个拨号连接，不过是个空的，里面没用用户名和密码等信息，需要用上面的拨号代码来指定拨号参数，不能使用<span style="color: rgb(0,0,0)">RasGetEntryDialParams来获取了。</span><br />上面的代码基本上是在网络上搜索所得，稍加修改，在这里整理一下。<br /><br />再补充一下删除连接的操作,代码如下：<br />
<div style="font-size: 13px; border-top: rgb(204,204,204) 1px solid; border-right: rgb(204,204,204) 1px solid; border-bottom: rgb(204,204,204) 1px solid; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: rgb(204,204,204) 1px solid; padding-right: 5px; width: 98%; background-color: rgb(238,238,238)"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: rgb(0,0,255)">void</span><span style="color: rgb(0,0,0)">&nbsp;RASManager::DeletePhoneBookEntry()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;RASENTRYNAME&nbsp;Entries[</span><span style="color: rgb(0,0,0)">15</span><span style="color: rgb(0,0,0)">];&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;cb,cEntries,dwRet;<br />&nbsp;&nbsp;&nbsp;&nbsp;Entries[</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">].dwSize</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(RASENTRYNAME);&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;cb</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,255)">sizeof</span><span style="color: rgb(0,0,0)">(Entries);<br />&nbsp;&nbsp;&nbsp;&nbsp;cEntries</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;dwRet</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">::RasEnumEntries(NULL,&nbsp;NULL,&nbsp;</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">Entries[</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">],&nbsp;</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">cb,&nbsp;</span><span style="color: rgb(0,0,0)">&amp;</span><span style="color: rgb(0,0,0)">cEntries);</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">如果函数成功，则返回0&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,128,0)"><br /></span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">if</span><span style="color: rgb(0,0,0)">(dwRet&nbsp;</span><span style="color: rgb(0,0,0)">==</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">)&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CHAR&nbsp;&nbsp;szRasEntryName[RAS_MaxEntryName&nbsp;</span><span style="color: rgb(0,0,0)">+</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">1</span><span style="color: rgb(0,0,0)">]</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">{</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">for</span><span style="color: rgb(0,0,0)">(UINT&nbsp;i</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">0</span><span style="color: rgb(0,0,0)">;i</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">cEntries;i</span><span style="color: rgb(0,0,0)">++</span><span style="color: rgb(0,0,0)">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(szRasEntryName,Entries[i].szEntryName);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RasDeleteEntry(NULL,szRasEntryName);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></div><span style="font-size: 9pt; font-family: 宋体"></span>要想实现自动启动拨号网络，就要使用Remote Access Service (RAS) API，这个API最早是在Windows for Workgroup 3.11中出现的，现在它已经成为Win32 API的一个组成部分。该API将整个拨号网络称为Phonebook，而每一个连接称为PhonebookEntry。你可以使用RasCreatePhonebookEntry来创建新的连接，用RasDial来拨号，而RasEnumEntries可以获得当前系统已有的所有连接，使用其它的RAS函数还可以获取或设置连接的参数。 RasEditPhonebookEntry函数将激活标准的Windows 95/NT属性对话框来修改连接的属性。你可以从Win32 API的手册找到所有相关函数的详细介绍。<br /><br />补充：在windows中一个拨号连接即为一个PhonrbookEntry以下称为电话薄记录或是连接。总的这些称为Phonebook。<img src ="http://www.cppblog.com/niewenlong/aggbug/198515.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2013-03-17 20:10 <a href="http://www.cppblog.com/niewenlong/archive/2013/03/17/198515.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC＋＋ 实现 拨号连接及动态IP地址获取</title><link>http://www.cppblog.com/niewenlong/archive/2013/03/17/198514.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Sun, 17 Mar 2013 11:51:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2013/03/17/198514.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/198514.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2013/03/17/198514.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/198514.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/198514.html</trackback:ping><description><![CDATA[<p>　　在Win32 API 函数中有一组用于实现远程连接服务RAS 的函数，利用这些函数通过编程可以实现建立和Internet 的拨号连接，并可获得Internet 分配给主机的动态IP 地址。<br /><br />一、建立拨号连接API<br /><br />　　建立拨号连接是利用函数RasDial() 实现的，该函数调用后立即返回，若成功返回0 值，否则返回非0 值。在拨号连接过程中，回调函数接收连接的状态信息及发生的错误代码。回调函数的原形如下：VOID WINAPI RasDialFunc(UINT unMsg,RASCONNSTATE rasconnstate,DWORD dwError) <br />　　由于在调用RasDialFunc 函数时，连接操作被挂起，因此，应用程序应尽快处理发生的事件并返回。可以在RasDialFunc 函数中调用PostMessage 函数，将事件通知消息送给窗口函数来处理。<br /><br />　　RASDIALPARAMS 结构定义如下：<br /><br />　　DWORD dwSize 结构变量的大小。<br /><br />　　TCHAR szEntryName[RAS_MaxEntryName ＋1] 　 拨号网络中建立的连接名。<br /><br />　　TCHAR szPhoneNumber[RAS_MaxPhoneNumber ＋1] 电话号码，若采用szEntryName 中定义的号码，置为NULL 值。<br /><br />　　TCHAR szCallbackNumber[RAS_MaxCallbackNumber ＋1] 回拨号码，不用时置为NULL。<br /><br />　　TCHAR szUserName[UNLEN ＋1] 用户标识。<br /><br />　　TCHAR szPassword[PWLEN ＋1] 用户口令。<br /><br />　　TCHAR szDomain[DNLEN ＋1] 用户权限验证域，若为NULL 采用RAS 服务器所在的域进行验证，若为&#8216;＊&#8217;采用szEntryName 中定义的域进行验证。<br /><br />　　RASCONNSTATE 枚举型结构，包含拨号连接过程中各种可能状态的定义。<br /><br />　　函数RasHangUp() 用来终止拨号连接，因程序需要一定的时间来结束连接，应用程序调用该函数后不能马上退出，需等待3 秒后才能退出。<br /><br />二、获取动态IP 地址API<br /><br />　　在VC 中是通过调用函数RasGetProjectionInfo() 来获取IP 地址的。<br />　　函数调用成功时返回0 值，此时在RASPPPIP 结构变量中的szIpAddress 就是动态IP 地址。<br /><br />三、程序实现<br /><br />　　程序是在Win 95 环境下，用VC ＋＋5.0 编写，并编译运行通过。完整的源程序清单如下：<br />// －－－　－－－－－－－－－－－－－<br />//file name ras.c<br />// －－－　－－－－－－－－－－－－－<br />＃include &lt; windows.h &gt;<br />＃include &lt; winuser.h &gt;<br />＃include &lt; string.h &gt;<br />＃include &lt; ras.h &gt;<br />＃include &lt; raserror.h &gt;<br />＃include "resource.h"<br />// 函数原形<br />LRESULT CALLBACK DialogProc(HWND hDlg, <br />UINT message, WPARAM wParam, LPARAM lParam);<br />void ShowMsg(HWND hwnd,char ＊msg);<br />LRESULT MsgDialDlgEvent(HWND hdlg, <br />UINT uMessage, WPARAM wparam, LPARAM lparam);<br />VOID WINAPI RasDialFunc<br />( UINT unMsg, RASCONNSTATE rasconnstate, <br />　DWORD dwError );<br />BOOL StartCon( HWND hWnd,char <br />　　　　　 ＊szUser,char ＊szPassword );<br />UINT GetRasConnState( RASCONNSTATE rasconn );<br />// 全局变量<br />HRASCONN　　hCon; //RAS 连接句柄<br />HWND　　　　hWin;<br />HINSTANCE　 hInst;<br />// －－－　－－－－－－－－－－－－－－<br />//windows 入口函数<br />// －－－　－－－－－－－－－－－－－－<br />int PASCAL WinMain( HINSTANCE hInstance, <br />HINSTANCE hPrevInstance，LPSTR lpszCmdLine,<br />int nCmdShow )<br />{<br />　　　hInst=hInstance;<br />　　　if ( DialogBox(hInstance,"RAS_DLG",NULL,<br />　　 (DLGPROC)DialogProc) == －1 )<br />　　　MessageBox(NULL,"建立对话框失败！",<br />　　 "TITLE",MB_OK);<br />　　　return 0;<br />}<br />// －－－－－－－－－－－－－－－－－<br />// 对话框窗口函数<br />// －－－－－－－－－－－－－－－－－<br />LRESULT CALLBACK DialogProc(HWND hDlg, <br />UINT message, WPARAM wParam, LPARAM lParam)<br />{<br />switch (message)<br />{<br />　 　case WM_INITDIALOG:<br />　 　 　hWin=hDlg;<br />　 　 　hCon=NULL;<br />　 　 　return (TRUE);<br />　 　case WM_RASDIALEVENT:<br />　 　 　MsgDialDlgEvent(hDlg,message,wParam,lParam);<br />　 　 　return (TRUE);<br />　 　case WM_COMMAND:<br />　 　 　switch (LOWORD(wParam))<br />　 　 　{<br />　 　case IDOK:<br />　 　 　StartCon( hDlg,"ljx@public.smptt.fj.cn",<br />"abbcd");<br />　 　 　break;<br />　 　case IDCANCEL:<br />　 　 　if ( hCon != NULL )<br />　 　 　{<br />　 　 　RasHangUp(hCon);<br />　 　 　Sleep(3000);<br />　 　 　}<br />　 　 　EndDialog(hDlg,TRUE);<br />　 　 　break;<br />　 　 　}<br />　 　 　break;<br />　 　}<br />　 　return (FALSE);<br />}<br />// ＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊<br />// 在列表框中显示信息<br />// ＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊<br />void ShowMsg(HWND hwnd,char ＊msg)<br />{<br />　　　int lnum;<br />　 　SendDlgItemMessage(hwnd,IDC_MSG,<br />　　　LB_ADD ?STRING,0,(long)msg );<br />　lnum=SendDlgItemMessage(hwnd,IDC_MSG,<br />　　　LB_GETCOUNT, 0,0);<br />　 　SendDlgItemMessage(hwnd,IDC_MSG,LB_SET ?<br />CURSEL,lnum －1,0);<br />　 　return;<br />}<br />// －－－－－－－－－－－－－－－－－<br />// BOOL StartCon( HWND hWnd )<br />// 建立拨号连接, 成功TRUE else FALSE<br />// szUser 和szPassword 分别为<br />　Internet 的用户名和口令<br />// －－－－－－－－－－－－－－－－－<br />BOOL StartCon<br />( HWND hWnd,char ＊szUser,char ＊szPassword )<br />{<br />　　RASDIALPARAMS rdParams;<br />　　DWORD dwRet;<br />　　　char szBuf[300];<br />　　　// 初始化变量<br />　　rdParams.dwSize = sizeof(RASDIALPARAMS);<br />　　lstrcpy(rdParams.szEntryName, "internet");<br />　　rdParams.szPhoneNumber[0] = '\0';<br />　　rdParams.szCallbackNumber[0] = '＊';<br />　　rdParams.szCallbackNumber[0] = '\0';<br />　　strcpy(rdParams.szUserName,szUser);<br />　　strcpy(rdParams.szPassword,szPassword);<br />　　　rdParams.szDomain[0] = '\0';<br />　　　hCon=NULL;<br />　　　// 以下开始异步拨叫网络<br />　　dwRet = RasDial( NULL, NULL, ＆rdParams, 0L, <br />　　　　　　(RASDIALFUNC) RasDialFunc, ＆hCon );<br />　　if ( dwRet )<br />　　{<br />　　if ( RasGetErrorString( (UINT)dwRet,<br />　　　　 (LPSTR)szBuf, 256 ) != 0 )<br />　 　wsprintf( (LPSTR)szBuf, <br />　　　&#8220;Undefined RAS Dial Error ( ％ld).", dwRet );<br />　 　ShowMsg(hWnd,szBuf);<br />　 　return FALSE;<br />　　}<br />　　　return TRUE;<br />}<br />// －－－－－－－－－－－－－－－<br />// RasDial 异步处理的回调函数<br />// unMsg　－发生的RAS 事件<br />// rasconnstate －连接进入的状态<br />// dwError　　　－发生的错误代码<br />// －－－－－－－－－－－－－－－<br />VOID WINAPI RasDialFunc<br />( UINT unMsg, RASCONNSTATE rasconnstate,<br />DWORD dwError )<br />{<br />　　PostMessage(hWin,<br />　　　　　　　WM_RASDIALEVENT,<br />　　　　　　　(WPARAM) rasconnstate,<br />　　　　　　　(LPARAM) dwError );<br />}<br />// －－－－－－－－－－－－－－－－<br />// RasDial() 返回的事件信息由该函数处理<br />// －－－－－－－－－－－－－－－－<br />LRESULT MsgDialDlgEvent(HWND hdlg, UINT uMessage,<br />WPARAM wparam, LPARAM lparam)<br />{<br />RASPPPIP rip;<br />DWORD ll,ret;<br />int num;<br />char szMessage[256];<br />LoadString(hInst,GetRasConnState<br />( (RASCONNSTATE) wparam ), szMessage, 64 );<br />ShowMsg(hdlg,szMessage);<br />if ( lparam )　// 发生错误<br />{<br />　 　if ( RasGetErrorString<br />　　 ( (UINT)lparam, szMessage, 256 ) != 0 )<br />　 　wsprintf( (LPSTR)szMessage, <br />　　　&#8220;出错Undefined RAS Dial Error." );<br />　 　ShowMsg(hdlg,szMessage);<br />　　　　　　return TRUE;<br />　　　　　　　　　<br />　　} <br />　　else if ( RASCS_DONE ＆wparam ) // 连接成功<br />　　{<br />　　　// 取动态分配的IP 地址<br />　　　ShowMsg(hdlg,"连接成功");<br />　　　rip.dwSize=sizeof(RASPPPIP);<br />　 　 if((ret=RasGetProjectionInfo(hCon,RASP_PppIp,<br />　　　(LPVOID) ＆rip,(LPDWORD) ＆ll )) != 0 )<br />　 　　{<br />　　　ShowMsg(hdlg,"取IP 地址失败");<br />　　　}<br />　　　else<br />　　　ShowMsg(hdlg,rip.szIpAddress);<br />　　}<br />　　return TRUE;<br />}<br />// －－－－－－－－－－－－－－－－<br />// 根据连接状态<br />　取字符串资源中对应的标号<br />// －－－－－－－－－－－－－－－－<br />UINT GetRasConnState( RASCONNSTATE rasconn )<br />{<br />　　switch( rasconn )<br />　　{<br />　　　　case RASCS_OpenPort:<br />　　　　　　return IDS_OPENPORT;<br />　　　　case RASCS_PortOpened:<br />　　　　　　return IDS_PORTOPENED;<br />　　　　case RASCS_ConnectDevice:<br />　　　　　　return IDS_CONNECTDEVICE;<br />　　　　case RASCS_DeviceConnected:<br />　　　　　　return IDS_DEVICECONNECTED; <br />　　　　case RASCS_AllDevicesConnected:<br />　　　　　　return IDS_ALLDEVICESCONNECTED; <br />　　　　case RASCS_Authenticate:<br />　　　　　　return IDS_AUTHENTICATE;<br />　　　　case RASCS_AuthNotify:<br />　　　　　　return IDS_AUTHNOTIFY;<br />　　　　case RASCS_AuthRetry:<br />　　　　　　return IDS_AUTHRETRY; <br />　　　　case RASCS_AuthCallback:<br />　　　　　　return IDS_AUTHCALLBACK;<br />　　　　case RASCS_AuthChangePassword:<br />　　　　　　return IDS_AUTHCHANGEPASSWORD;<br />　　　　case RASCS_AuthProject:<br />　　　　　　return IDS_AUTHPROJECT; <br />　　　　case RASCS_AuthLinkSpeed:<br />　　　　　　return IDS_AUTHLINKSPEED; <br />　　　　case RASCS_AuthAck: <br />　　　　　　return IDS_AUTHACK; <br />　　　　case RASCS_ReAuthenticate:<br />　　　　　　return IDS_REAUTHENTICATE;<br />　　　　case RASCS_Authenticated:<br />　　　　　　return IDS_AUTHENTICATED; <br />　　　　case RASCS_PrepareForCallback:<br />　　　　　　return IDS_PREPAREFORCALLBACK;<br />　　　　case RASCS_WaitForModemReset:<br />　　　　　　return IDS_WAITFORMODEMRESET; <br />　　　　case RASCS_WaitForCallback:<br />　　　　　　return IDS_WAITFORCALLBACK; <br />　　　　case RASCS_Interactive:<br />　　　　　　return IDS_INTERACTIVE; <br />　　　　case RASCS_RetryAuthentication: <br />　　　　　　return IDS_RETRYAUTHENTICATION;<br />　　　　case RASCS_CallbackSetByCaller: <br />　　　　　　return IDS_CALLBACKSETBYCALLER; <br />　　　　case RASCS_PasswordExpired:<br />　　　　　　return IDS_PASSWORDEXPIRED; <br />　　　　case RASCS_Connected:<br />　　　　　　return IDS_CONNECTED;<br />　　　　case RASCS_Disconnected:<br />　　　　　　return IDS_DISCONNECTED;<br />　　　　default:<br />　　　　　　return IDS_UNDEFINED_ERROR;<br />　　}<br />} 　</p>
<div class="tang_downimg11"></div>
<!--  JavaScript专用链代码 --><span style="font-family: Arial"></span>---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<br /><br /><br /><strong style="font-family: Arial; color: red">华丽的分割线</strong><br /><br /><br />---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<br />序：近日，有位朋友问到用VC实现拨号上网的程序，今天在网上无意中发现了这篇文章，于是便转载过来，希望对这位朋友有所帮助！ <br />正文： <br />&nbsp; &nbsp;大家知道，在netants、download expert等软件中都带有定时拨号上网下载软件的功能。而一般用户的拨号上网，利用的是windows的remote access service（ras，远程访问服务）。下面介绍一下其在visual c＋＋下的实现。 <br />　　visual c＋＋为我们提供了包含ras api声明的&#8220;ras.h&#8243;头文件。要在程序中实现拨号上网功能，其大致过程如下： <br />　　1. 利用modem拨号进行连接，应使用rasdial函数。 <br />　　其声明如下： <br />　　dword ras dial(lprasdialextensions lpras dialextensions,lpctstr lpszphonebook,lprasdialparams lp ras dialparams,dword dw notifier type,lpvoid lpv notifier, lphrasconn lph ras conn ) <br />　　参数说明： <br />　　lprasdialextensions和lpszphonebook：仅在windows nt下有效，在windows 95下，这两个参数被忽略。 <br />　　lprasdialparams：这个参数很重要，它指向一个rasdialparams结构，该结构包含以下几个成员： <br />　　dwsize：应设定为sizeof（rasdialparams）； <br />　　szentryname和szphonenumber：这两个参数有联系，szentryname可以指定要建立的连接，比方说&#8220;我的连接&#8221;等等，这是处理用户已经在&#8220;拨号网络&#8221;里建立的连接的。这时，modem将拨打你在&#8220;我的连接&#8221;中设定的isp号码，此时szphonenumber成员设为空字符串&#8220;&#8221;即可；如果你要在程序中自行指定要拨打的isp号码的话，szentryname可以设定为空字符串&#8220;&#8221;，此时应设置szphonenumber为你的isp号码（169，663等），特别的，对于用201电话卡来上网的情况，可以设为&#8220;201,,,账号，密码＃，，isp号码＃&#8221;（其中&#8220;，&#8221;表示停顿一段时间（以等待确认账号，密码等），你可以根据自己所在位置的线路状况自行调节。 szcallbacknumber，szdomain：设为空串&#8220;&#8221;即可。 szusername，szpassword：登录用户名和密码。如169公用账号guest，guest。 <br />　　其他成员不必设置。 <br />　　dwnotifiertype：指定是由窗口还是由回调函数来处理确认消息。通过确认消息我们可以得到rasdial过程的当前状态。如&#8220;正在打开段口&#8221;，&#8220;正在验证用户名和密码&#8221;等。也可设为null。 dwnotifier：指定处理确认消息的窗口或回调函数。也可设为null。 <br />　　lphrasconn：指向一个类型为hrasconn的变量。在调用rasdial前必须指定为null，rasdial若成功返回，则将ras连接的句柄存放于它所指向的变量中。我们也可以通过此句柄来断开连接。 <br />　　只要在程序中适当位置调用rasdial函数即可建立连接。 <br />　　2. 理确认消息以得到拨号过程的当前状态。 <br />　　我们以指定窗口来处理确认消息为例说明如何得到拨号过程的当前状态。 <br />　　在处理确认消息的对话框类（或视图类等）的实现代码中加入： <br />　　const uint wm_rasevent = ::registerwindowmessagea(rasdialevent)； <br />　　在message map中手工加入消息映射：(＊＊＊＊是你定义的对话框类名称) <br />　　begin_message_map(＊＊＊＊, cdialog) <br />　　file://afx_msg_map(＊＊＊＊) <br />　　&#8230;&#8230; <br />　　on_registered_message(wm_rasevent, onrasdialevent)（＜－加入此句） <br />　　file://afx_msg_map <br />　　end_message_map() <br />　　加入成员函数处理消息： <br />　　lresult cdialinfo::onrasdialevent(wparam wp, lparam lp) <br />　　{ <br />　　rasconnstate rasstate= (rasconnstate)wp; <br />　　clistbox ＊info =(clistbox ＊)getdlgitem(idc_infolist); <br />　　file://用listbox 控件(id为idc－infolist)来显示状态) <br />　　switch(rasstate) <br />　　{ <br />　　case rascs_openport: <br />　　info&#8594;addstring(_t(&#8243;打开端口&#8230;&#8230;&#8243;)); <br />　　break; <br />　　case rascs_portopened: <br />　　info&#8594;addstring(_t(&#8243;端口已打开.&#8243;)); <br />　　break; <br />　　case rascs_connectdevice: <br />　　info&#8594;addstring(_t(&#8243;连接设备&#8230;&#8230;&#8243;)); <br />　　break; <br />　　case rascs_deviceconnected: <br />　　info&#8594;addstring(_t(&#8243;设备已连接.&#8243;)); <br />　　break; <br />　　case rascs_authenticate: <br />　　info&#8594;addstring(_t(&#8243;验证用户及密码&#8243;)); <br />　　break; <br />　　case rascs_authenticated: <br />　　info&#8594;addstring(_t(&#8243;通过&#8243;)); <br />　　break; <br />　　case rascs_connected: <br />　　info－&gt;addstring(_t(&#8243;已连接&#8243;)); <br />　　reak; <br />　　case rascs_disconnected: <br />　　info－&gt;addstring(_t(&#8243;连接已断开&#8243;)); <br />　　m_hrasconn=null; <br />　　file://可定义类型为hrasconn的成员变量m_hrasconn来保存ras连接的句柄。 <br />　　file://在调用rasdial时用指向m_hrasconn的指针作为lphrasconn参数。 <br />　　file://既然用m_hrasconn来保存连接句柄，连接断开后应重置为null. <br />　　break; <br />　　default: <br />　　return (lresult)0; <br />　　} <br />　　return (lresult)0; <br />　　} <br />　　3. 断开连接： <br />　　if (m_hrasconn != null) <br />　　{ <br />　　rashangup(m_hrasconn); <br />　　m_hrasconn = null; <br />　　m_ondial=true; <br />　　:sleep(2000); <br />　　} <br />　　注意 ： <br />　　你也许注意到了以上代码中的sleep函数，这里是必需的。需要一定时间来断开连接。如果不等待一段时间，计算机有可能无法正常关闭端口。导致下一次无法拨号，只有重新启动windows才能解决。要预防此问题也可以调用rasgetconnectstatus函数，方法如下： <br />　　rasconnstatus rstatus； <br />　　while（rasgetconnectstatus（m_hrasconn，＆rstatus）！=error_invalid_handle） <br /><br />　　{ <br />　　：：sleep（0）； <br />　　} <br />　　4．在以下情况下： <br />　　&#9312; 浏览网页时有时会出现停止响应，重启explorer后任务栏上的连接状态图标也许会消失。 <br />　　&#9313; 希望在连接成功后，退出程序，再次执行此程序可选择断开连接。 <br />　　可以调用rasenumconnection函数来得到当前连接的句柄。 <br />　　举例如下： <br />　　hrasconn hrasconnect;dword dwbufffersize, dwnumofconnections;//缓冲区大小，连接数 <br />　　lprasconn lprasconn; <br />　　lprasconn = new rasconn［3】;//最多可得到3个连接句柄，客户端程序其实不必设为3，因连接数有限，大部分仅一个连接。 <br />　　lprasconn［0】.dwsize = sizeof(rasconn); <br />　　dwbufffersize = 32＊ sizeof(rasconn);//求出由3个rasconn结构构成的缓冲区大小 <br />　　rasenumconnections(lpras conn, ＆dw buffer size, ＆dw numof connections)；//此函数若成功则返回零。 <br />　　for(dword i=0; i 　　{ <br />　　hrasconnect = lprasconn［i】.hrasconn;//rasconn结构的hrasconn成员为ras连接句柄 <br />　　 rashangup(hrasconnect); <br />　　 ::sleep(2000); <br />　　} <br />　　delete ［】 lprasconn; <br />　　在windows 98，visual c＋＋ 6.0下调试通过。 <br />　　这样，一个实现基本拨号上网功能的程序就完成了。如果你要了解更多有关情况或服务器端程序设计，可以参考msdn&#8594;platform sdk&#8594;networking and distributed services&#8594;remote access service的有关内容<br />---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<br /><br /><br /><strong style="font-family: Arial; color: red">华丽的分割线</strong><br /><br /><br />---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------<br /><br />
<p>背景：代替手工自动进行PPPOE拨号</p>
<p>相关知识：</p>
<p>主要使用的函数：</p>
<p>The <strong>RasDial</strong> function establishes a RAS connection between a RAS client and a RAS server. The connection data includes callback and user-authentication information</p><pre>DWORD RasDial(<br />
__in  LPRASDIALEXTENSIONS lpRasDialExtensions,<br />
__in  LPCTSTR lpszPhonebook,<br />
__in  LPRASDIALPARAMS lpRasDialParams,<br />
__in  DWORD dwNotifierType,<br />
__in  LPVOID lpvNotifier,<br />
__in  LPHRASCONN lphRasConn<br />
);<br />
<br />
</pre>
<h3>Return Value</h3>
<p>If the function succeeds, the return value is ERROR_SUCCESS and a handle to the RAS connection is returned in the variable pointed to by <em>lphRasConn</em> .</p>
<p>If the function fails, the return value is from <a href="http://msdn.microsoft.com/en-us/library/bb530704%28v=VS.85%29.aspx">Routing and Remote Access Error Codes</a> or Winerror.h.</p>
<p>&nbsp;</p>
<p>更多消息请查看 ：</p>
<p>http://msdn.microsoft.com/en-us/library/aa377004(VS.85).aspx</p>
<p>&nbsp;</p>
<p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; RASDIALPARAMS&nbsp; ms;<br />&nbsp;&nbsp;&nbsp; RASDIALPARAMS params;<br />&nbsp;&nbsp;&nbsp; HRASCONN handle=NULL;&nbsp;&nbsp;&nbsp; <br /><br />&nbsp;&nbsp;&nbsp; memset(&amp;ms, '/0', sizeof(params));<br />&nbsp;&nbsp;&nbsp; params.dwSize=sizeof(RASDIALPARAMS);<br /><br />&nbsp;&nbsp;&nbsp; CString entryname;<br />&nbsp;&nbsp;&nbsp; CString tmp;<br />&nbsp;&nbsp;&nbsp; tmp.Format("%d", i);<br />&nbsp;&nbsp;&nbsp; entryname="UE"+tmp;//需要拨号的名称，也就是建立的宽带连接的名称，如UE0<br />&nbsp;&nbsp;&nbsp; strcpy(params.szEntryName,entryname); <br /><br />&nbsp;&nbsp;&nbsp; strcpy(params.szPhoneNumber,"");<br />&nbsp;&nbsp;&nbsp; strcpy(params.szCallbackNumber,"");<br /><br />&nbsp;&nbsp;&nbsp; strcpy(params.szUserName,"tm500");&nbsp; //用户名<br />&nbsp;&nbsp;&nbsp; strcpy(params.szPassword, "tm500");&nbsp; //密码<br />&nbsp;&nbsp;&nbsp; strcpy(params.szDomain,&nbsp; "");&nbsp; <br /><br />&nbsp;&nbsp;&nbsp; Message +="/n"+entryname+"dailying up ......";<br />&nbsp;&nbsp;&nbsp; UpdateData(TRUE);<br /><br />&nbsp;&nbsp; //指定的拨号连接。<br /><br />&nbsp;&nbsp;&nbsp; int a =RasDial(NULL, NULL, &amp;params, NULL, NULL, &amp;handle);<br />&nbsp;&nbsp;&nbsp; if (a!=ERROR_SUCCESS) <br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; MessageBox("正在拨打的计算机没有应答，稍后请再试"); <br /><br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Message +="/n"+entryname+"dailying up failed....../n";<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; UpdateData(TRUE);<br /><br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; DWORD off=RasHangUp(handle);<br /><br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //SendMessage(WM_CLOSE);<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (off==0)<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;MessageBox("连接已断开");<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//printf("连接已断开.../n");<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else{<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //printf("断开连接出错.../n");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MessageBox("断开连接出错.");<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }</p><br /><br /><br /><br /><br />
<table width="100%">
<tbody>
<tr>
<td><script type="text/javascript" src="http://www.rosoo.net/ad/js_ad_468x15_100.js"></script><br />
<p><a href="/a/list_100_1.html" target="_blank"><u>C++</u></a> 拨号函数演示</p><pre><ol class="dp-cpp"><li class="alt"><span class="comment">/*********************************/</span><span>&nbsp;</span></li><li><span class="comment">//code&nbsp;By&nbsp;PE_luck&nbsp;</span><span>&nbsp;</span></li><li class="alt"><span>&nbsp;</span></li><li><span class="comment">//百度:http://zhidao.baidu.com/question/73758972.html</span><span>&nbsp;</span></li><li class="alt"><span>&nbsp;</span></li><li><span class="comment">//2008-10-31&nbsp;</span><span>&nbsp;</span></li><li class="alt"><span>&nbsp;</span></li><li><span class="comment">/*********************************/</span><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;</span></li><li><span class="preprocessor">#include&nbsp;&lt;windows.h&gt;</span><span>&nbsp;</span></li><li class="alt"><span class="preprocessor">#include&nbsp;&lt;stdio.h&gt;</span><span>&nbsp;</span></li><li><span class="preprocessor">#include&nbsp;&lt;Ras.h&gt;</span><span>&nbsp;</span></li><li class="alt"><span class="preprocessor">#pragma&nbsp;comment(lib,"rasapi32.lib")&nbsp;</span><span>&nbsp;</span></li><li><span>&nbsp;</span></li><li class="alt"><span class="datatypes">int</span><span>&nbsp;main(</span><span class="datatypes">int</span><span>&nbsp;argc,</span><span class="datatypes">char</span><span>&nbsp;*argv[])&nbsp;</span></li><li><span>{&nbsp;</span></li><li class="alt"><span>printf(<span class="string">"UserName:"</span><span>);&nbsp;&nbsp;</span></span></li><li><span class="datatypes">char</span><span>&nbsp;user[100]={0};&nbsp;</span></li><li class="alt"><span>scanf(<span class="string">"%s"</span><span>,user);&nbsp;</span></span></li><li><span>printf(<span class="string">"PassWord:"</span><span>);&nbsp;</span></span></li><li class="alt"><span class="datatypes">char</span><span>&nbsp;pass[100]={0};&nbsp;</span></li><li><span>scanf(<span class="string">"%s"</span><span>,pass);&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;</span></li><li><span class="comment">//如果想自动请将上面的代码直接替换成你的用户名和密码&nbsp;</span><span>&nbsp;</span></li><li class="alt"><span>&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;RASDIALPARAMSA&nbsp;rdParams;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;rdParams.dwSize=<span class="keyword">sizeof</span><span>(RASDIALPARAMSA);&nbsp;</span></span></li><li><span>strcpy(rdParams.szEntryName,<span class="string">"宽带连接"</span><span>);&nbsp;</span><span class="comment">//连接名称是你的拨号名称</span><span>&nbsp;</span></span></li><li class="alt"><span>rdParams.szPhoneNumber[0]=<span class="string">'\0'</span><span>;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;rdParams.szCallbackNumber[0]=<span class="string">'\0'</span><span>;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;strcpy(rdParams.szUserName,user);&nbsp;</span></li><li><span>strcpy(rdParams.szPassword,pass);&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;rdParams.szDomain[0]=<span class="string">'\0'</span><span>;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;HRASCONN&nbsp;hRscon=NULL;&nbsp;</span></li><li class="alt"><span class="datatypes">DWORD</span><span>&nbsp;retn=&nbsp;RasDialA(NULL,NULL,&amp;rdParams,0L,NULL,&amp;hRscon);&nbsp;&nbsp;</span></li><li><span>&nbsp;</span></li><li class="alt"><span class="keyword">if</span><span>&nbsp;(retn==0)&nbsp;</span></li><li><span>{&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;printf(<span class="string">"已经连接上...\n"</span><span>);&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;<span class="comment">//断开函数</span><span>&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="comment">/*</span>&nbsp;</span></li><li><span class="comment">&nbsp;&nbsp;&nbsp;DWORD&nbsp;off=&nbsp;RasHangUp(&amp;hRscon);</span>&nbsp;</li><li class="alt"><span class="comment">&nbsp;&nbsp;&nbsp;if&nbsp;(off==0)</span>&nbsp;</li><li><span class="comment">&nbsp;&nbsp;&nbsp;{</span>&nbsp;</li><li class="alt"><span class="comment">&nbsp;&nbsp;&nbsp;printf("连接已断开...\n");</span>&nbsp;</li><li><span class="comment">&nbsp;&nbsp;&nbsp;}else</span>&nbsp;</li><li class="alt"><span class="comment">&nbsp;&nbsp;&nbsp;printf("断开连接出错...\n");</span>&nbsp;</li><li><span class="comment">&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="comment">//具体的细节慢慢扩充吧...仅仅演示一下...</span><span>&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;0;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;</span></li><li><span>printf(<span class="string">"连接出错...\n"</span><span>);&nbsp;</span></span></li><li class="alt"><span class="keyword">return</span><span>&nbsp;0;&nbsp;</span></li></ol></pre>
<div class="dede_pages"></div></td></tr></tbody></table><img src ="http://www.cppblog.com/niewenlong/aggbug/198514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2013-03-17 19:51 <a href="http://www.cppblog.com/niewenlong/archive/2013/03/17/198514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC实现HTTP协议的GET和POST方法</title><link>http://www.cppblog.com/niewenlong/archive/2012/06/09/178227.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Sat, 09 Jun 2012 13:55:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2012/06/09/178227.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/178227.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2012/06/09/178227.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/178227.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/178227.html</trackback:ping><description><![CDATA[<p>以下是两个文件：HttpClient.h HttpClient.cpp 一个类 <br />（错误检测部分没有加入） <br />使用方法 <br />1：get方式 <br />CHttpClient conn; <br />CString value="<a href="http://8crystal.com/test.asp">http://8crystal.com/test.asp</a>"; <br />value=conn.doGet(value); <br />2：post方式 <br />CHttpClient conn; <br />CString value="<a href="http://8crystal.com/test.asp">http://8crystal.com/test.asp</a>"; <br />conn.addParam("name1","value1"); <br />conn.addParam("name2","value2"); <br />conn.addParam("name3","value3"); <br />conn.addParam("name4","value4"); <br />conn.addParam("name5","value5"); <br />conn.addParam("name6","value6"); <br />value=conn.doPost(value); <br /><br />// HttpClient.h: interface for the CHttpClient class. <br />// <br />////////////////////////////////////////////////////////////////////// <br /><br />#if !defined(AFX_HTTPCLIENT_H__EA769DCB_AAB9_47CD_BD87_FBD6913592C5__INCLUDED_) <br />#define AFX_HTTPCLIENT_H__EA769DCB_AAB9_47CD_BD87_FBD6913592C5__INCLUDED_ <br /><br />#if _MSC_VER &gt; 1000 <br />#pragma once <br />#endif // _MSC_VER &gt; 1000 <br />#include "wininet.h" <br />#include "afxinet.h" <br />class CHttpClient <br />{ <br />public: <br />void addParam(CString name,CString value); <br />CString doPost(CString href); <br />CString doGet(CString href); <br />CHttpClient(); <br />virtual ~CHttpClient(); <br /><br />private: <br />CString CONTENT; <br />int CL; <br />CStringList values; <br />CStringList names; <br />}; <br /><br />#endif // !defined(AFX_HTTPCLIENT_H__EA769DCB_AAB9_47CD_BD87_FBD6913592C5__INCLUDED_) <br /><br />++++++++++++++++++++++++++++++++++++++ <br /><br /><br />// HttpClient.cpp: implementation of the CHttpClient class. <br />// <br />////////////////////////////////////////////////////////////////////// <br /><br />#include "stdafx.h" <br />#include "emailsenderv2.h" <br />#include "HttpClient.h" <br /><br />#ifdef _DEBUG <br />#undef THIS_FILE <br />static char THIS_FILE[]=__FILE__; <br />#define new DEBUG_NEW <br />#endif <br /><br />////////////////////////////////////////////////////////////////////// <br />// Construction/Destruction <br />////////////////////////////////////////////////////////////////////// <br /><br />CHttpClient::CHttpClient() <br />{ <br /><br />} <br /><br />CHttpClient::~CHttpClient() <br />{ <br /><br />} <br /><br />CString CHttpClient::doGet(CString href) <br />{ <br />CString httpsource=""; <br />CInternetSession session1(NULL,0); <br />CHttpFile* pHTTPFile=NULL; <br />try{ <br />pHTTPFile=(CHttpFile*)session1.OpenURL(href); <br />//session1. <br />}catch(CInternetException){ <br />pHTTPFile=NULL; <br />} <br />if(pHTTPFile) <br />{ <br />CString text; <br />for(int i=0;pHTTPFile-&gt;ReadString(text);i++) <br />{ <br />httpsource=httpsource+text+"\r\n"; <br />} <br />pHTTPFile-&gt;Close(); <br />delete pHTTPFile; <br />}else <br />{ <br /><br />} <br />return httpsource; <br />} <br /><br />CString CHttpClient::doPost(CString href) <br />{ <br />CString httpsource=""; <br />CInternetSession session1; <br />CHttpConnection* conn1=NULL; <br />CHttpFile* pFile = NULL; <br />CString strServerName; <br />CString strObject; <br />INTERNET_PORT nPort; <br />DWORD dwServiceType; <br />AfxParseURL((LPCTSTR)href,dwServiceType, strServerName, strObject, nPort); <br />DWORD retcode; <br />char* outBuff = CONTENT.GetBuffer(1000); <br />try <br />{ <br />conn1 = session1.GetHttpConnection(strServerName,nPort); <br />pFile = conn1-&gt;OpenRequest(0,strObject,NULL,1,NULL,"HTTP/1.1",INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_NO_AUTO_REDIRECT); <br />pFile -&gt; AddRequestHeaders("Content-Type: application/x-www-form-urlencoded"); <br />pFile -&gt; AddRequestHeaders("Accept: */*"); <br />pFile -&gt; SendRequest(NULL,0,outBuff,strlen(outBuff)+1); <br />pFile -&gt; QueryInfoStatusCode(retcode); <br />} <br />catch (CInternetException * e){}; <br />if(pFile) <br />{ <br />CString text; <br />for(int i=0;pFile-&gt;ReadString(text);i++) <br />{ <br />httpsource=httpsource+text+"\r\n"; <br />} <br />pFile-&gt;Close(); <br />}else <br />{ <br /><br />} <br />return httpsource; <br />delete pFile; <br />delete conn1; <br />session1.Close(); <br />} <br /><br />void CHttpClient::addParam(CString name, CString value) <br />{ <br />names.AddTail((LPCTSTR)name); <br />values.AddTail((LPCTSTR)value); <br />CString eq="="; <br />CString an="&amp;"; <br />CONTENT=CONTENT+name+eq+value+an; <br />CL=CONTENT.GetLength(); <br />} <br /></p><img src ="http://www.cppblog.com/niewenlong/aggbug/178227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2012-06-09 21:55 <a href="http://www.cppblog.com/niewenlong/archive/2012/06/09/178227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DirectX与OpenGL方面的经典电子书下载 </title><link>http://www.cppblog.com/niewenlong/archive/2008/11/21/67465.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Fri, 21 Nov 2008 03:11:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/11/21/67465.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/67465.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2008/11/21/67465.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/67465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/67465.html</trackback:ping><description><![CDATA[<p style="FONT-FAMILY: Verdana">Programming MS DirectShow for Digital Video &amp; TV.chm<br><a href="http://219.139.240.53/itebook/MS"><u><font color=#0000ff>http://219.139.240.53/itebook/MS</font></u></a> Press - Programming MS DirectShow for Digital Video &amp; TV.chm</p>
<p style="FONT-FAMILY: Verdana">MICROSOFT.DIRECTX.9.PROGRAMMABLE.GRAPHICS.PIPELINE.rar<br><a href="http://219.139.240.53/itebook/MS"><u><font color=#0000ff>http://219.139.240.53/itebook/MS</font></u></a> Press - MICROSOFT.DIRECTX.9.PROGRAMMABLE.GRAPHICS.PIPELINE.rar</p>
<p style="FONT-FAMILY: Verdana">Strategy.Game.Programming.with.DirectX.9.0.chm<br><a href="http://219.139.240.53/itebook/1556229224-Strategy.Game.Programming.with.DirectX.9.0.chm"><u><font color=#0000ff>http://219.139.240.53/itebook/1556229224-Strategy.Game.Programming.with.DirectX.9.0.chm</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Strategy Game Programming with DirectX 9.0.ra<br><a href="http://219.139.240.53/itebook/1556229224-Strategy"><u><font color=#0000ff>http://219.139.240.53/itebook/1556229224-Strategy</font></u></a> Game Programming with DirectX 9.0.rar</p>
<p style="FONT-FAMILY: Verdana">Introduction to 3D Game Programming with DirectX 9.0.rar<br><a href="http://219.139.240.53/itebook/1556229135-Introduction"><u><font color=#0000ff>http://219.139.240.53/itebook/1556229135-Introduction</font></u></a> to 3D Game Programming with DirectX 9.0.rar</p>
<p style="FONT-FAMILY: Verdana">Programming Role-playing Games With DirectX<br><a href="http://219.139.240.53/itebook/20040129174.rar"><u><font color=#0000ff>http://219.139.240.53/itebook/20040129174.rar</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Real-time Rendering Tricks and Techniques in DirectX <br><a href="http://219.139.240.53/itebook/20040129198.rar"><u><font color=#0000ff>http://219.139.240.53/itebook/20040129198.rar</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Wordware.Publishing.Directx.9.User.Interfaces.Design.and.Implementation<br><a href="http://219.139.240.53/itebook/20040829361.rar"><u><font color=#0000ff>http://219.139.240.53/itebook/20040829361.rar</font></u></a></p>
<p style="FONT-FAMILY: Verdana">MICROSOFT DIRECTX 9 PROGRAMMABLE GRAPHICS PIPELINE.rar<br><a href="http://219.139.240.53/itebook/MS"><u><font color=#0000ff>http://219.139.240.53/itebook/MS</font></u></a> Press - MICROSOFT DIRECTX 9 PROGRAMMABLE GRAPHICS PIPELINE.rar</p>
<p style="FONT-FAMILY: Verdana">Wordware.Advanced.3D.Game.Programming.With.DirectX.9.0<br><a href="http://219.139.240.53/itebook/20040829359.rar"><u><font color=#0000ff>http://219.139.240.53/itebook/20040829359.rar</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Wordware.Advanced.3D.Game.Programming.With.DirectX.9.0<br><a href="http://219.139.240.53/itebook/20040829356.rar"><u><font color=#0000ff>http://219.139.240.53/itebook/20040829356.rar</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Advanced 3D Game Programming with DirectX 9.0.chm<br><a href="http://219.139.240.53/itebook/Advanced"><u><font color=#0000ff>http://219.139.240.53/itebook/Advanced</font></u></a> 3D Game Programming with DirectX 9.0.chm</p>
<p style="FONT-FAMILY: Verdana">Premier.Press.Beginning.Direct3D.Game.Programming.2nd.Edition.chm<br><a href="http://219.139.240.53/itebook/Premier.Press.Beginning.Direct3D.Game.Programming.2nd.Edition.chm"><u><font color=#0000ff>http://219.139.240.53/itebook/Premier.Press.Beginning.Direct3D.Game.Programming.2nd.Edition.chm</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Sams.Managed.DirectX.9.Kick.Start.Graphics.And.Game.Programming.chm <br><a href="http://219.139.240.53/itebook/Sams.Managed.DirectX.9.Kick.Start.Graphics.And.Game.Programming.chm"><u><font color=#0000ff>http://219.139.240.53/itebook/Sams.Managed.DirectX.9.Kick.Start.Graphics.And.Game.Programming.chm</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Wordware.Introduction.To.3D.Game.Programming.With.DirectX.9.0.chm<br><a href="http://219.139.240.53/itebook/Wordware.Introduction.To.3D.Game.Programming.With.DirectX.9.0.chm"><u><font color=#0000ff>http://219.139.240.53/itebook/Wordware.Introduction.To.3D.Game.Programming.With.DirectX.9.0.chm</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Wordware.Publishing.DirectX.9.Audio.Exposed.Interactive.Audio.Development.chm<br><a href="http://219.139.240.53/itebook/Wordware.Publishing.DirectX.9.Audio.Exposed.Interactive.Audio.Development.chm"><u><font color=#0000ff>http://219.139.240.53/itebook/Wordware.Publishing.DirectX.9.Audio.Exposed.Interactive.Audio.Development.chm</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Wordware.Strategy.Game.Programming.With.DirectX.9.0.chm<br><a href="http://219.139.240.53/itebook/Wordware.Strategy.Game.Programming.With.DirectX.9.0.chm"><u><font color=#0000ff>http://219.139.240.53/itebook/Wordware.Strategy.Game.Programming.With.DirectX.9.0.chm</font></u></a></p>
<p style="FONT-FAMILY: Verdana">Wordware-DirectX 9 Audio Exposed Interactive Audio Development.rar<br><a href="http://219.139.240.53/itebook/1556222882-Wordware-DirectX"><u><font color=#0000ff>http://219.139.240.53/itebook/1556222882-Wordware-DirectX</font></u></a> 9 Audio Exposed Interactive Audio Development.rar</p>
<p style="FONT-FAMILY: Verdana">Focus On 2D in Direct3D <br><a href="http://219.139.240.53/itebook/20040827355.rar"><u><font color=#0000ff>http://219.139.240.53/itebook/20040827355.rar</font></u></a><br></p>
<p style="FONT-FAMILY: Verdana">&nbsp;</p>
<p style="FONT-FAMILY: Verdana">OpenGL Programming Guide (Red Book).rar<br><a href="http://219.139.240.53/itebook/0201461382-OpenGL"><u><font color=#0000ff>http://219.139.240.53/itebook/0201461382-OpenGL</font></u></a> Programming Guide (Red Book).rar</p>
<p style="FONT-FAMILY: Verdana">Using OpenGL in Visual C++<br><a href="http://219.139.240.53/itebook/20040229088.rar"><u><font color=#0000ff>http://219.139.240.53/itebook/20040229088.rar</font></u></a></p>
<p style="FONT-FAMILY: Verdana">OpenGL Programming Guide.rar<br><a href="http://219.139.240.53/itebook/Addison"><u><font color=#0000ff>http://219.139.240.53/itebook/Addison</font></u></a> Wesley - OpenGL Programming Guide.rar</p>
<p style="FONT-FAMILY: Verdana">2_Advanced_Graphics_Programming_Techniques_Using_Opengl<br><a href="http://219.139.240.53/itebook/20040827059.rar"><u><font color=#0000ff>http://219.139.240.53/itebook/20040827059.rar</font></u></a><br></p>
</span><br>
<img src ="http://www.cppblog.com/niewenlong/aggbug/67465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-11-21 11:11 <a href="http://www.cppblog.com/niewenlong/archive/2008/11/21/67465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows下架设Subversion服务器</title><link>http://www.cppblog.com/niewenlong/archive/2008/10/28/65285.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Tue, 28 Oct 2008 02:51:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/28/65285.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/65285.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2008/10/28/65285.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/65285.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/65285.html</trackback:ping><description><![CDATA[<p style="FONT-FAMILY: 幼圆">作者：indian</p>
<p style="FONT-FAMILY: 幼圆">版本：v1.2</p>
<p style="FONT-FAMILY: 幼圆">修订：2008年1月24日11:45:35</p>
<p style="FONT-FAMILY: 幼圆">出处：<a href="http://indian.blog.163.com/blog/static/10881582007112415021751"><font color=#1b6d5d><u>blog.kysf.net</u></font></a></p>
<p style="MARGIN-LEFT: 31.5pt; TEXT-INDENT: -31.5pt; FONT-FAMILY: 幼圆">版权：作者保留对本文的一切修改、发布等权力。任何人想要转载本文部分或全部内容时，必须保留包括作者、版本、修订、出处、版权，共五项信息。对本文的参考引用，则不受限制。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">关键词：subversion, 安装配置, 权限, 目录访问</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">1 前言<br>2 基本概念<br>　2.1 什么是版本控制<br>　2.2 什么是 Subversion<br>　2.3 版本库（repository）<br>3 安装配置<br>　3.1 安装独立服务器 SVNServer<br>　3.2 安装 ApacheSVN 服务器<br>4 FAQ<br>5 参考资料</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<h1 style="TEXT-ALIGN: center">1、前 言</h1>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">花了72小时，终于把 Subversion 初步掌握了。从一个连&#8220;什么是版本控制&#8221;都不知道的门外汉，到配置出精确至每目录访问的入门者，中间还卡了一天时间。其中费了许多气力，摸索实验了多次，还差点放弃了，但是收获是巨大的。现把我的配置和学习过程写下来，供大家参考，也让初学者少走弯路。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">由于本人不会 Unix/Linux （正在学习中），故仅以 Windows 平台为例讲解，Unix/Linux 平台请参考相关资料。如其中有谬误的地方，包括错别字，请联系我修订。</p>
<p style="COLOR: red; TEXT-INDENT: 2em; FONT-FAMILY: 幼圆"><strong>技术在分享中进步！</strong></p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<h1 style="TEXT-ALIGN: center" align=center>2、基本概念</h1>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">2.1、什么是版本控制</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">简单点来说，版本控制就是数据仓库，它可以记录你对文件的每次更改。这样，就算你在昏天黑地的改了几个月后老板说不要了，还是按照过去那样，你也不会抓狂，简单的恢复版本操作就搞定一切。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">2.2、什么是 Subversion</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">Subversion是一个自由/开源版本控制系统，它管理文件和目录可以超越时间。一组文件存放在中心版本库，这个版本库很像一个普通的文件服务器，只是它可以记录每一次文件和目录的修改，这便使你可以取得数据以前的版本，从而可以检查所作的更改。从这个方面看，许多人把版本控制系统当作一种&#8220;时间机器&#8221;。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">Subversion可以通过网络访问它的版本库，从而使用户可以在不同的电脑上使用。一定程度上可以说，允许用户在各自的地方修改同一份数据是促进协作。进展可能非常的迅速，并没有一个所有的改变都会取得效果的通道，由于所有的工作都有历史版本，你不必担心由于失去某个通道而影响质量，如果存在不正确的改变，只要取消改变。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">一些版本控制系统也是软件配置管理（SCM）系统，这种系统经过特定的精巧设计来管理源代码，有许多关于软件开发的特性—本身理解编程语言、或者提供构建程序的工具。然而，Subversion不是这样一个系统，它是一个通用系统，可以管理任何类型的文件集，对你这可能是源代码，对别人，可能是一个货物报价单或者是书稿等。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">2.3、版本库（repository）</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">Subversion 的核心就是 rpository ，中文翻译成&#8220;版本库&#8221;。就是位于服务器端，统一管理和储存数据的地方。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<h1 style="TEXT-ALIGN: center">3、安装配置</h1>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<h3>3.1 安装独立服务器 SVNServer</h3>
<p style="FONT-FAMILY: 幼圆">环境</p>
<p style="FONT-FAMILY: 幼圆">OS：Windows XP SP2</p>
<p style="FONT-FAMILY: 幼圆">Web：Apache 2.2.6</p>
<p style="FONT-FAMILY: 幼圆">SVN：svn-win32-1.4.6</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">一、准备工作</p>
<p style="FONT-FAMILY: 幼圆">1、获取 Subversion 服务器程序</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">到官方网站（http://subversion.tigris.org/）下载最新的服务器安装程序。目前最新的是1.4.6版本，具体下载地址在：<a href="http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100&amp;expandFolder=8100&amp;folderID=91"><font color=#1b6d5d><u>http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=8100&amp;expandFolder=8100&amp;folderID=91</u></font></a> ，注意找 for apache 2.2.x 版本的。</p>
<p style="FONT-FAMILY: 幼圆">2、获取 TortoiseSVN 客户端程序</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">从官方网站 <a href="http://tortoisesvn.net/downloads"><font color=#1b6d5d><u>http://tortoisesvn.net/downloads</u></font></a> 获取最新的 TortoiseSVN 。TortoiseSVN 是一个客户端程序，用来与 subvers 服务器端通讯。Subversion 自带一个客户端程序 svn.exe ,但 TortoiseSVN 更好操作，提高效率。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">二、安装服务器端和客户端</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">首先安装 Apache 2.2.6 ，具体安装方法大家参考相关资料，或者参看我写的《<a href="http://indian.blog.163.com/blog/static/1088158200755105546704"><font color=#1b6d5d><u>Windows下安装Apache 2.2.x</u></font></a>》。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">其次安装 Subversion（以下简称SVN）的服务器端和客户端。下载下来的服务器端是个 zip 压缩包，直接解压缩即可，比如我解压到 E:\subversion 。客户端安装文件是个 exe 可执行文件，直接运行按提示安装即可，客户端安装完成后提示重启。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">三、建立版本库（Repository）</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">运行Subversion服务器需要首先要建立一个版本库（Repository）。版本库可以看作是服务器上集中存放和管理数据的地方。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">开始建立版本库。首先建立 e:\svn 空文件夹作为所有版本库的根目录。然后，进入命令行并切换到subversion的bin目录。输入如下命令：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">svnadmin create E:\svn\repos1</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">此命令在 E:\svn 下建立一个版本库 repos1 。repos1 下面会自动生成一些文件夹和文件。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">我们也可以使用 TortoiseSVN 图形化的完成这一步：</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">先建立空目录 E:\svn\repos1 ，注意一定是要空的。然后在 repos1 文件夹上&#8220;右键-&gt;TortoiseSVN-&gt;Create Repository here...&#8221;，然后可以选择版本库模式，这里使用默认的FSFS即可，然后就创建了一系列文件夹和文件，同命令行建立的一样。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">四、运行独立服务器</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">此时 subversion 服务还没有开始，只是通过它的命令建立了版本库。继续在刚才的命令窗口输入：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">svnserve.exe --daemon</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">svnserve 将会在端口 3690 等待请求，--daemon（两个短横线）选项告诉 svnserve 以守护进程方式运行，这样在手动终止之前不会退出。注意不要关闭命令行窗口，关闭窗口会把 svnserve 停止。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">为了验证svnserve正常工作，使用TortoiseSVN -&gt; Repo-browser 来查看版本库。在弹出的 URL 对话框中输入：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">svn://localhost/svn/repos1</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">点 OK 按钮后就可以看见 repos1 版本库的目录树结构了，只不过这时 repos1 是个空库。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">你也可以使用--root选项设置根位置来限制服务器的访问目录，从而增加安全性和节约输入svnserve URL的时间：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">svnserve.exe --daemon --root drive:\path\to\repository</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">以前面的测试作为例，svnserve 将会运行为：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">svnserve.exe --daemon --root e:\svn</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">然后TortoiseSVN中的版本库浏览器URL缩减为：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">svn://localhost/repos1</div>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">五、配置用户和权限</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">用文本编辑器打开E:\svn\repos1\conf目录，修改svnserve.conf：</p>
<p style="FONT-FAMILY: 幼圆">将：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆"># password-db = passwd</div>
<p style="FONT-FAMILY: 幼圆">改为：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">password-db = passwd</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">即去掉前面的 # 注释符，注意前面不能有空格。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">然后修改同目录的passwd文件，增加一个帐号：</p>
<p style="FONT-FAMILY: 幼圆">将：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">[users]<br># harry = harryssecret<br># sally = sallyssecret</div>
<p style="FONT-FAMILY: 幼圆">增加帐号：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">[users]<br>#harry = harryssecret<br>#sally = sallyssecret<br>test = test</div>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">六、初始化导入</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">下面就是将我们的数据（项目）导入到这个版本库，以后就由版本库管理我们的数据。我们的任何改动都回被版本库记录下来，甚至我们自己丢失、改错数据时版本库也能帮我们找回数据。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">比如，我在 d:\wwwroot 下有个 guestbook 文件夹，里面存放的是我编写的留言簿程序。在此文件夹上&#8220;右键 -&gt; TortoiseSVN -&gt; Import...&#8221; ，在弹出对话框的&#8220;URL of repository&#8221;输入&#8220;svn://localhost/repos1/guestbook&#8221;。在&#8220;Import message&#8221;输入&#8220;导入整个留言簿&#8221;作为注释。<br>点 OK 后要求输入帐号。我们在用户名和密码处都输入 test 。完成后 guestbook 中的内容全部导入到了 svn://localhost/svn/repos1/guestbook 。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">我们看到在 e:\svn\repos1 没有任何变化，连个 guestbook 文件夹都没有建立，唯一的变化就是e:\svn\repos1容量变大了。实际上我们源guestbook中的内容已经导入 repos1 版本库了，源 guestbook 文件夹可以删除了。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">需要注意的是，这一步操作可以完全在另一台安装了 TortoiseSVN 的客户机上进行。例如运行svnserve的主机的IP是133.96.121.22，则URL部分输入的内容就是&#8220;svn://133.96.121.22&#8221; 。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">七、基本操作流程</p>
<p style="FONT-FAMILY: 幼圆">1、取出（check out）</p>
<p style="FONT-FAMILY: 幼圆">取出版本库到一个工作拷贝：</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">来到任意空目录下，比如在f分区建立一个空文件夹 f:\work 。&#8220;右键 -&gt; SVN Checkout&#8221;。在&#8220;URL of repository&#8221;中输入&#8220;svn://localhost/svn/repos1/guestbook&#8221;，这样我们就得到了一份 guestbook 中内容的工作拷贝。</p>
<p style="FONT-FAMILY: 幼圆">2、存入（check in）/提交（commit）</p>
<p style="FONT-FAMILY: 幼圆">在工作拷贝中作出修改并提交：</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">在 guestbook 工作拷贝中随便打开一个文件，作出修改，然后&#8220;右键 -&gt; SVN Commit... &#8221;。这样我们就把修改提交到了版本库，版本库根据情况存储我们提交的数据。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">在修改过的文件上&#8220;右键 -&gt; TortoiseSVN -&gt; Show Log&#8221; ，可以看到对这个文件所有的提交。在不同的 revision 条目上&#8220;右键 -&gt; Compare with working copy&#8221;，我们可以比较工作拷贝的文件和所选 revision 版本的区别。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<h3>3.2 安装 ApacheSVN 服务器</h3>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">Subversion的设计包括一个抽象的网络层，这意味着版本库可以通过各种服务器进程访问。理论上讲，Subversion可以使用无限数量的网络协议实现，目前实践中存在着两种服务器。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<ul>
    <li>SVNServer：svnserve 是一个小的（也叫轻型的）、独立服务器，使用自己定义的协议和客户端。（作者注：以下称这种服务器为&#8220;svnserver服务器&#8221;，上面的安装配置就是安装svnserver服务器。）<br><br>&nbsp;
    <li>ApacheSVN：Apache是最流行的web服务器，通过使用 mod_dav_svn 模块，Apache可以访问版本库，并且可以使客户端使用HTTP的扩展协议WebDAV/DeltaV进行访问。（作者注：以下称这种服务器为&#8220;ApacheSVN服务器&#8221;） </li>
</ul>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">通过 Http 协议访问版本库是 Subversion 的亮点之一。<strong>ApacheSVN服务器</strong> 具备了许多 <strong>svnserve服务器 </strong>没有的特性，使用上更加灵活，但是有一点难于配置，灵活通常会带来复杂性。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">由于 Subversion 需要版本化的控制，因此标准的 Http 协议不能满足需求。要让 Apache 与 Subversion 协同工作，需要使用 WebDAV（Web-based Distributed Authoring and Versioning：）Web 分布式创作和版本控制）。WebDAV 是 HTTP 1.1 的扩展，关于 WebDAV 的规范和工作原理，可以参考 <a href="http://www.ietf.org/rfc/rfc2518.txt"><font color=#1b6d5d><u>IETF RFC 2518</u></font></a> 。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">一、必备条件</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">为了让你的版本库使用HTTP网络，你必需具备以下几个条件：</p>
<ol>
    <li>配置好httpd 2.2.x，并且使用mod_dav启动。
    <li>为mod_dav安装mod_dav_svn插件。
    <li>配置你的httpd.conf，使http协议能访问版本库。 </li>
</ol>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">下面以我的配置过程详细讲解。</p>
<p style="FONT-FAMILY: 幼圆">环境：</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">OS：Windows XP SP2</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">Web：Apache 2.2.6</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">SVN：svn-win32-1.4.6</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">二、安装</p>
<p style="FONT-FAMILY: 幼圆">1、安装Apache</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">具体安装方法见：《<a href="http://indian.blog.163.com/blog/static/1088158200755105546704"><font color=#1b6d5d><u>Windows下安装Apache 2.2.x</u></font></a>》</p>
<p style="FONT-FAMILY: 幼圆">2、安装 Subversion</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">将下载下来的 svn-win32-1.4.6.zip 直接解压即可，比如我解压到 e:\subversion 。<br>从Subversion安装目录的 bin 子目录将 intl3_svn.dll、libdb44.dll、mod_authz_svn.so、mod_dav_svn.so 拷贝到Apache的模块目录（Apache 安装目录的 modules 文件夹）。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">三、基本的Apache配置</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">修改Apache的配置文件 <em>httpd.conf </em>，使用LoadModule来加载mod_dav_svn模块。</p>
<p style="FONT-FAMILY: 幼圆">将：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">#LoadModule dav_module modules/mod_dav.so</div>
<p style="FONT-FAMILY: 幼圆">改成：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">LoadModule dav_module modules/mod_dav.so</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">即去掉前面的&#8220;#&#8221;号。</p>
<p style="FONT-FAMILY: 幼圆">添加：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">LoadModule dav_svn_module modules/mod_dav_svn.so</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">一定确定它在 mod_dav 之后。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">现在你已经设置了Apache和Subversion，但是Apache不知道如何处理Subversion客户端，例如TortoiseSVN。为了让Apache知道哪个目录是用来作为Subversion版本库，你需要使用编辑器（例如记事本）编辑Apache的配置文件。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">在配置文件最后添加如下几行：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">&lt;Location /repository/&gt;<br>&nbsp; DAV svn<br>&nbsp; SVNPath e:/svn/repos1<br>&lt;/Location&gt;</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">这个配置告诉Apache首先需要启用 dav_module，然后加载 dav_svn_module 。版本库对外的URL是：http://服务器IP/repository/ ，所有的Subversion版本库在物理上位于e:/svn/repos1/ 。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">配置完毕后重新启动 Apache，打开浏览器，输入 http://服务器IP/ repository/ 将会看到如下画面：</p>
<p style="MARGIN: 25pt; FONT-FAMILY: 幼圆; TEXT-ALIGN: center"><img height=104 alt="" src="http://img.blog.163.com/photo/94bq16Cb2CSM3YMOo_WcWQ==/880172252174552815.jpg" width=324 border=0></p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">这表示 Apache 的 dav_svn 模块已经可以正常工作了。用户可以使用任何一种 Subversion 的客户端通过 Http 协议访问你的版本库。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">如果想要指定多个版本库，可以用多个 Location 标签，也可以使用 SVNParentPath 代替 SVNPath，例如在 e:\svn 下有多个版本库 repos1，repos2 等等，用如下方式指定：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">&lt;Location /repository/&gt;<br>　DAV svn<br>　SVNParentPath e:/svn<br>&lt;/Location&gt;</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">&#8220;SVNParentPath e:/svn &#8221; 表示 e:\svn 下的每个子目录都是一个版本库。可以通过 http://服务器IP/repository/repos1/，http://服务器IP/repository/repos2/ 来访问。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">现在你的版本库任何人都可以访问，并且有完全的写操作权限。也就是说任何人都可以匿名读取，修改，提交，以及删除版本库中的内容(注：这时不需要配置E:\svn\repos\conf\svnserve.conf 文件，并且也不需要启动E:\subversion\bin\svnserve.exe。因为提交是通过Apache的dav模块处理的，而不是由svnservice处理。)。我们用 TortoiseSVN 客户端验证即知。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">显然大部分场合这是不符合需求的。那么如何进行权限设置呢，Apache 提供了基本的权限设置：</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">四、认证选项</p>
<p style="FONT-FAMILY: 幼圆">1、基本 HTTP 认证</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">最简单的客户端认证方式是通过 HTTP 基本认证机制，简单的使用用户名和密码来验证一个用户的身份。Apache提供了一个 htpasswd 工具来管理一个用户文件，这个文件包含用户名和加密后的密码，这些就是你希望赋予 Subversion 特别权限的用户。htpasswd 可以在 Apache 的 bin 安装目录下找到。具体使用方法如下：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">
<p style="FONT-FAMILY: 幼圆">创建用户文件：<br>htpasswd -c E:\usr\Apache2.2\bin\passwd.conf username</p>
<p style="FONT-FAMILY: 幼圆">添加新用户（-m 表示以 MD5 加密密码，可选项）：<br>htpasswd [-m] E:\usr\Apache2.2\bin\passwd.conf Newusername</p>
<p style="FONT-FAMILY: 幼圆">更改用户密码：<br>htpasswd [-m] E:\usr\Apache2.2\bin\passwd.conf username</p>
<p style="FONT-FAMILY: 幼圆">删除用户（要用大写的 D ）：<br>htpasswd &#8211;D E:\usr\Apache2.2\bin\passwd.conf username</p>
</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">接下来修改 httpd.conf，在 Location 标签中加入如下内容：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">AuthType Basic<br>AuthName "svn repos"<br>AuthUserFile E:/usr/Apache2.2/bin/passwd.conf<br>Require valid-user</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">说明：</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">AuthType Basic：启用基本的验证，比如用户名/密码对。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">AuthName "svn repos"：当一个认证对话框弹出时，出现在认证对话框中的信息。（最好用英文，TortoiseSVN 不支持中文，安装语言包除外。）</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">AuthUserFile E:/usr/Apache2.2/bin/passwd：指定E:\usr\Apache2.2\bin\passwd为用户文件，用来验证用户的用户名及密码。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">Require valid-user：限定用户只有输入正确的用户名及密码后才能访问这个路径</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">重新启动 Apache ，打开浏览器访问版本库。Apache 会提示你输入用户名和密码来认证登陆了，现在只有 passwd 文件中设定的用户才可以访问版本库。也可以配置只有特定用户可以访问，替换上述 "Require valid-user" 为 "Require user tony robert" 将只有用户文件中的 tony 和 robert 可以访问该版本库。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">有的时候也许不需要这样严格的访问控制，例如大多数开源项目允许匿名的读取操作，而只有认证用户才允许写操作。为了实现更为细致的权限认证，可以使用 Limit 和 LimitExcept 标签。例如：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">&lt;LimitExcept GET PROPFIND OPTIONS REPORT&gt;<br>&nbsp; require valid-user<br>&lt;/LimitExcept&gt;</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">以上配置将使匿名用户有读取权限，而限制只有 passwd 中配置的用户可以使用写操作。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">如果这还不能满足你的要求，你希望精确的控制版本库目录访问，可以使用 Apache 的 mod_authz_svn 模块对每个目录进行认证操作。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">2、用 mod_authz_svn 进行目录访问控制</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">首先需要让 Apache 将 mod_authz_svn 模块加载进来。在 Subversion 的安装目录中找到 mod_auth_svn 模块，将其拷贝到 Apache 安装目录的 modules 子目录下。修改 httpd.conf 文件，添加：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">LoadModule authz_svn_module modules/mod_authz_svn.so</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">现在可以在 Location 标签中使用 authz 的功能了。一个基本的 authz 配置如下：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">&lt;Location /repository/&gt;<br>&nbsp; DAV svn<br>&nbsp; SVNParentPath e:/svn<br><br>&nbsp; # our access control policy<br>&nbsp; AuthzSVNAccessFile E:/usr/Apache2.2/bin/accesspolicy.conf<br><br>&nbsp; # try anonymous access first, resort to real<br>&nbsp; # authentication if necessary.<br>&nbsp; Satisfy Any<br>&nbsp; Require valid-user<br><br>&nbsp; # how to authenticate a user<br>&nbsp; AuthType Basic<br>&nbsp; AuthName "Subversion repository"<br>&nbsp; AuthUserFile E:/usr/Apache2.2/bin/passwd.conf<br>&lt;/Location&gt;</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">AuthzSVNAccessFile 指向的是 authz 的策略文件，详细的权限控制可以在这个策略文件中指定。访问文件 accesspolicy.conf 的语法与svnserve.conf和 Apache 的配置文件非常相似，以（#）开头的行会被忽略；在它的简单形式里，每一小节命名一个版本库和一个里面的路径；认证用户名是在每个小节中的选项名；每个选项的值描述了用户访问版本库的级别：r（只读）或者rw（读写），如果用户没有提到或者值留空，访问是不允许的； * 表示所有用户，用它控制匿名用户的访问权限；@符号区分组和用户。如：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">[groups]<br>committers = paulex, richard<br>developers = jimmy, michel, spark, sean<br><br>[/]<br>* = r<br>@committers = rw <br><br>[/branches/dev]<br>@developers = rw <br><br>[/tags]<br>tony = rw <br>[/private]<br>* = <br>@committers= r<br>&nbsp;</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">使用 SVNParentPath 代替 SVNPath 来指定多个版本库的父目录时，其中所有的版本库都将按照这个策略文件配置。例如上例中 tony 将对所有版本库里的 /tags 目录具有读写权限。如果要对具体每个版本库配置，用如下的语法：</p>
<div style="BORDER-RIGHT: 1pt solid; PADDING-RIGHT: 4pt; BORDER-TOP: 1pt solid; PADDING-LEFT: 4pt; BACKGROUND: silver; PADDING-BOTTOM: 4pt; MARGIN: 30pt 21pt; BORDER-LEFT: 1pt solid; PADDING-TOP: 4pt; BORDER-BOTTOM: 1pt solid; FONT-FAMILY: 幼圆">[groups]<br>project1_committers = paulex, richard<br>project2_committers = jimmy, michel, spark, tony, Robert<br><br>[repos1:/] <br>* = r <br>@ project1_committer = rw<br><br>[repos2:/] <br>* = r <br>@ project2_committer = rw<br>&nbsp;</div>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">这样项目1的 project1_committer 组只能对 repos1 版本库下的文件具有写权限而不能修改版本库 repos2 ，同样项目2的 project2_commiter 组也不能修改 repos1 版本库的文件。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<h1 style="TEXT-ALIGN: center">4、FAQ</h1>
<p style="FONT-FAMILY: 幼圆">1、路径或权限不足时将出现错误信息提示：</p>
<p style="FONT-FAMILY: 幼圆">http://localhost （路径不对）<br>Error * PROPFIND request failed on '/' PROPFIND of '/': 200 OK (http://localhost)</p>
<p style="FONT-FAMILY: 幼圆">http://localhost/svn （权限不足） <br>Error * PROPFIND request failed on '/svn' PROPFIND of '/svn': 403 Forbidden (http://localhost)</p>
<p style="FONT-FAMILY: 幼圆">http://localhost/svn/repos （正常显示）</p>
<p style="FONT-FAMILY: 幼圆">http://localhost/repos （权限不允许） <br>Error * PROPFIND request failed on '/repos' PROPFIND of '/repos': 405 Method Not Allowed (http://localhost)</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">2、不启动E:\subversion\bin\svnserve.exe ，但启动了ApacheSVN ，访问（tortoiseSVN &#8211;&gt; Repo &#8211; browser）或提交（SVN Commit）情形如下：</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">现象：svn://localhost/svn/repos 不能访问或提交，提示：Error * Can't connect to host 'localhost': 由于目标机器积极拒绝，无法连接。 但 file:///e:/svn/repos 和 http://localhost/svn/repos 可以访问或提交。</p>
<p style="TEXT-INDENT: 2em; FONT-FAMILY: 幼圆">原因：svn:// 是独立服务器 svnserver 自己的协议。file:/// 是本地访问，即服务器端和客户端在一个机器上。</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">参考资料：<br><a href="http://subversion.tigris.org/"><font color=#1b6d5d><u>Subversion 官方网站</u></font></a>：Subversion 的官方网站，提供最权威的介绍和最新的下载。<br><a href="http://www.subversion.org.cn/svnbook/"><font color=#1b6d5d><u>Subversion 中文手册</u></font></a>：Subversion 简体中文官方网站翻译的中文手册。<br><a href="http://www.subversion.org.cn/tsvndoc/"><font color=#1b6d5d><u>TortoiseSVN 中文文档</u></font></a>：Subversion 简体中文官方网站翻译的 TortoiseSVN 中文文档。<br><a href="http://www.iusesvn.com/"><font color=#1b6d5d><u>我用SVN中文论坛</u></font></a>：国内人气非常旺的 SVN 中文交流论坛。<br>《<a href="http://www.subversion.org.cn/index.php?option=com_content&amp;task=view&amp;id=78&amp;Itemid=9"><font color=#1b6d5d><u>用Apache和Subversion搭建安全的版本控制环境</u></font></a>》：IBM 工程师写的基于 Linux 的 SVN 教程。<br><a href="http://baike.baidu.com/"><font color=#1b6d5d><u>百度百科</u></font></a>：由全体网民共同撰写的百科全书</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">~ 全文完~</p>
<p style="FONT-FAMILY: 幼圆">&nbsp;</p>
<p style="FONT-FAMILY: 幼圆">　　　　　　　　　　印第安</p>
<p style="FONT-FAMILY: 幼圆">　　　　　　2007年12月23日23:37:41　v1.0 初稿<br>　　　　　　2007年12月25日2:24:53　v1.1 更新。更改了几处路径，使之更加便于Win下调试。全文重新排版，阅读条理更清晰。 <br>　　　　　　2008年1月24日11:45:35　v1.2 修订。修改几处书写错误（谢谢山东济南的网易博友242）；修改1个关键配置路径。</p>
<img src ="http://www.cppblog.com/niewenlong/aggbug/65285.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-28 10:51 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/28/65285.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>svn版本控制</title><link>http://www.cppblog.com/niewenlong/archive/2008/10/28/65284.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Tue, 28 Oct 2008 02:49:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/28/65284.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/65284.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2008/10/28/65284.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/65284.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/65284.html</trackback:ping><description><![CDATA[<div style="BORDER-RIGHT: #cccccc 1px dashed; PADDING-RIGHT: 10px; BORDER-TOP: #cccccc 1px dashed; DISPLAY: block; PADDING-LEFT: 10px; FONT-SIZE: 12pt; PADDING-BOTTOM: 10px; BORDER-LEFT: #cccccc 1px dashed; PADDING-TOP: 10px; BORDER-BOTTOM: #cccccc 1px dashed; FONT-FAMILY: 幼圆">
<p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <caption>文档规则 </caption>
    <tbody>
        <tr>
            <td>[本地工作区] ：work copy ，本地工作副本；</td>
        </tr>
        <tr>
            <td>[主项目]：引用共用模块的新项目（工程）</td>
        </tr>
        <tr>
            <td>最新版本（HEAD revision）：版本库里文件或目录的最新版本</td>
        </tr>
        <tr>
            <td>SA ：SVN服务器的管理员</td>
        </tr>
        <tr>
            <td>PRA ：单个项目库的管理员，或者是项目负责人</td>
        </tr>
        <tr>
            <td>User ：普通工作人员</td>
        </tr>
        <tr>
            <td>WC ：work copy ，本地工作副本</td>
        </tr>
    </tbody>
</table>
</p>
<p><br><strong>1. 版本控制原则</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;SVN（或者其他版本控制软件）只是一个版本控制的辅助工具，不可能把所有的问题都自动解决掉。尤其，对于冲突这个麻烦事儿，项目成员在项目进程中要尽量通过优化流程来解决，而不是将希望寄托于软件工具来自动解决一切问题。<br>建议的开发过程组织：<br>&nbsp;&nbsp;&lt;1&gt;. 随行就市&gt;<br>项目刚开始阶段，单独开发；项目稳定阶段，完整开发。项目开发初期，各个项目成员负责自己的文件夹（或者模块），与SVN服务器间的更新、提交等操作只需 要针对自己负责的文件夹（或者模块）就行了，他人的文件夹（或者模块）可以不必关心；项目稳定阶段，也就是每天的变更量很小了，所有项目成员与SVN服务 器的更新、提交等操作需要针对项目的所有文件夹（或者模块），各个项目成员在其本地编译时本地工作区的全部项目程序（或者资料）均为最新的版本，保证项目 作为整体能够顺利运行。<br>&nbsp;&nbsp; &lt;2&gt;. 能躲就躲<br>尽量保证一份文件只有一个项目成员在编辑。举例说明：程序员A负责底层中文件 DBAccess.cs的编写，如果程序员B的工作要求他为DBAccess.cs增加两个方法，程序员B应该通知程序员A来增加而不是自己增加；如果此 时A非常繁忙需要B自己增加，就需要B先更新本地的DBAccess.cs，然后开始修改，修改完成后立即提交并通知A更新本地的文件，通过缩短提交间隔 来减少冲突。<br><strong>2. 基于版本控制的开发流程</strong><br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/1.gif"><br>版本控制下的软件开发基本流程<br><span class=STYLE1>注意：</span>上述的流程中没有考虑测试和审核的步骤。<br><strong>3.各阶段中svn的使用方法介绍</strong><br>&lt;1&gt;.安装后的常规设置<br>&nbsp;&nbsp;(1). 中文界面的设置<br>将TortoiseSVN的操作语言设置为中文，控制文件夹使用&#8220;_SVN&#8221;以便支持Asp.net项目。<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/2.gif"><br>&nbsp;&nbsp;(2).忽略文件<br>&nbsp;&nbsp;为防止在提交操作时将不必要的文件上传到SVN服务器上，可将项目中不需要受SVN控制的文件和文件夹通过设置忽略选项的方式排除掉。常被忽略的文件 有 _* obj *.db *.resharper* *.Load *.pdb *.bak。可以根据实际需要来修改忽略参数， 每个需要忽略的文件（文件夹）名称之间用空格作分隔符，需要忽略的文件夹只要写文件夹名称就行，例如 obj，忽略obj文件夹及所包含文件；_*忽略所有_（下划线）开头的文件夹及所包含文件。注意，这个设置仅对本机有效，而且对本机的所有项目的本地工 作区有效，对其他项目组成员没有影响。被忽略的文件仍可以通过&#8220;添加&#8221;命令使其受SVN控制。<br><br>操作界面如下图，只需将忽略参数填写在&#8220;全局忽略模式&#8221;后的文本框中即可。 <br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/3.gif"><br>&nbsp;&nbsp;(3).配置强制注释<br>&nbsp;&nbsp;项目负责人通过设置项目的TortoiseSVN:logminisize设置为5，以便强制注释。设置方法：在项目的本地工作区文件夹上点击鼠标右 键选择&#8220;属性&#8221;，进入 Subversion标签，选中TortoiseSVN: logminisize，确保复选框&#8220;递归应用该属性&#8221;选中，取值设为5，其意思是指提交的注释最短长度为五个字。注意，这个设置对其他项目成员的也有 效，但是对别的SVN客户端工具（如AnkhSVN）无效。 <br>&lt;2&gt;. 初始化版本库<br>初始化版本库有两种常用的方式：<br>&nbsp;&nbsp;1. 直接&#8220;导入Import&#8230;&#8221;<br>对要执行导入操作得项目文件夹进行如下清理：<br>&nbsp;&nbsp;&nbsp;&nbsp;(1). 把项目中不需要的文件删除。（临时文件、编译器创建的文件，比如*.obj、二进制文件等。）<br>&nbsp;&nbsp;&nbsp;&nbsp;(2). 把文件夹和子文件夹中的所有文件整理一遍。虽然你可以在导入之后再来进行重命名或删除等操作，但是还是推荐你在导入之前把你的项目整理好。<br>在资源管理器（windows explorer）中选择项目(本地硬盘上)的根文件夹，单击鼠标右键，选择导入Import&#8230;命令，跳出一个对话框：<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/4.gif"><br>&nbsp;&nbsp;在这个对话框中你需要填写你要将项目导入仓库的URL地址（svn必须小写）。导入信息（Important Message）是用来记录日志信息的。注意：与&#8220;忽略样式exclude pattern&#8221;匹配的文件或文件夹不会被导入，除非选择了&#8220;包含忽略的文件&#8221;选项。<br>按下&#8220;确定&#8221;按钮后，TortoiseSVN就开始把整个文件夹树（包括所有文件）导入到仓库。用来做&#8220;导入Import&#8221;操作的这个文件夹的名字不会出 现在仓库中，只有文件夹中的内容会出现。注意：刚才用来做&#8220;导入Import&#8221;操作的这个文件夹并没有处于版本控制下！要获取一份处于版本控制之下的[本 地工作区]副本，你需要对刚导入的版本做一次&#8220;检出Checkout&#8221;操作。<br>&nbsp;&nbsp;2.&#8220;检出Checkout&#8221;—&gt;&#8220;提交Commit&#8221;<br>新建一个空文件夹作为[本地工作区]的存放文件夹（建议与项目同名），在文件夹上（或者文件夹里）单击鼠标右键后在命令菜单中选择&#8220;检出Checkout&#8230;&#8221;，出现操作窗口。注意：只能检出Checkout到一个空文件夹。<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/5.gif"><br>&nbsp;&nbsp;把本地硬盘上的项目文件夹中的内容（不要复制项目的根文件夹）全部复制到[本地工作区] 文件夹中，并对文件夹中进行清理操作（同&#8220;导入Import&#8221;操作前的清理操作）。然后选择[本地工作区] 文件夹单击鼠标右键跳出菜单，选择命令&#8220;提交Commit&#8230;&#8221;：<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/6.gif"><br>提交对话框会显示每一个有修改的文件，包括新增的，删除的，还有没有版本控制的。如果不想&#8220;提交Commit&#8221;某个有变更的文件，只需取消勾选那个文件即可。相反，如果要提交某个未受版本控制的文件，只需勾选它就可以然后&#8220;提交Commit&#8221;即可。<br>&nbsp;&nbsp;3.日常开发中的SVN操作<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/7.gif"><br><br>0.版本号的解释<br>SVN系统中的版本号准确应该叫做&#8220;修订版本号&#8221;，每当版本库接受了一个提交Commit，文件系统进入了一个新的状态，叫做一次修订（revision），每一个修订版本被赋予一个独一无二的、递增的自然数，这个自然数就是修订版本号。<br>受控项目中任何一个受控文件/文件夹进行了修改提交Commit操作，项目的版本号就会提升一次，没有进行修改的文件/文件夹其版本号不会发生变化。受控 项目每一个装态都包含项目的所有文件/文件夹，引起该次版本号增加的即修改了的文件/文件夹保存新副本，没有发生修改的文件/文件夹保存引用，因此项目中 的文件/文件夹可能与项目的版本号不同。<br><br>0.更新(Update)工作副本<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/8.gif"><br>&nbsp;&nbsp;把他人做的修改融合到自己的本地副本当中，这个把改动从服务器拿到本地的过程就是&#8220;更新Update&#8221;。&#8220;更新Update&#8221;操作可以针对一个文件， 或几个被选择的文件，或某个文件夹中的所有文件。选择想要进行&#8220;更新Update&#8221;操作的文件和（或）文件夹，单击鼠标右键，在菜单中选择&#8220;更新 Update&#8221;， 执行窗口显示正在&#8220;更新Update&#8221;的进度。他人做的修改会合并到自己的文件中，而自己所做的修改会被保留。如果不能合并，将会出现冲突（红色文字显 示），冲突的文件图标将出现标志。<br>命令 &#8220;更新至版本Update to Revision...&#8221; 可以使[本地工作区]更新到自己选择的一个特定版本。<br><br>0.解决冲突<br>&nbsp;&nbsp;选择<img alt="" src="http://www.qudee.com/scv20071110/images/tech/0.gif">的文件，点击鼠标右键菜单中选择&#8220;编辑冲突Edit Conflict&#8221;来打开合并工具或冲突编辑器，做一些必要的修改，然后保存文件。然后选择菜单中的&#8220;已解决的Resolved&#8221;命令执行，接着提交commit修改到仓库。<br>注意：命令&#8220;已解决的Resolved&#8221;并没有真正的解决冲突，它只不过是把&#8220;文件名称.扩展名.mine&#8221; 和 &#8220;文件名称.扩展名.r*&#8221;（r*中星号代表任意位数字，即版本号）删除，并允许你提交修改而已。因此，建议在有冲突发生时要先执行&#8220;编辑冲突Edit Conflict&#8221; 再执行&#8220;已解决的Resolved&#8221;；如果确信自己的修改是正确的，不需要保留他人的修改，可将文件名称.扩展名.mine去掉&#8220;.mine&#8221;后缀，并把 &#8220;.r*&#8221;后缀的文件和&#8220;<img alt="" src="http://www.qudee.com/scv20071110/images/tech/0.gif">&#8221;的文件删除，然后正常&#8220;提交Commit&#8221;，版本库中将保存自己的版本。<br><br>0.提交修改到仓库<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/9.gif"><br>&nbsp;&nbsp;强烈建议在提交之前，应该确认[本地工作区] 是最新的。可以直接作一次&#8220;更新Update&#8221;操作，或者先&#8220;检查更新Check for Modifications&#8221;看看在本地或在服务器上哪些文件修改过。如果没有这样的操作直接提交的话，很有可能出现冲突现象。&#8220;检查更新Check for Modifications&#8221;操作后的结果界面如下： <br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/10.gif"><br>&nbsp;&nbsp;如果[本地工作区] 是最新的，并且没有冲突，就可以提交你的修改了。选中你想要提交的任意文件或文件夹，然后选择在菜单中选择&#8220;提交Commit&#8230;&#8221;在提交对话框中双击一个 有修改的文件，可以启动外挂的比较工具来显示修改细节。 在按下&#8220;确定OK&#8221;按钮之后，会显示提交的进程情况。<br><br>0.比较差异(Diff)<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/11.gif"><br>&nbsp;&nbsp;[本地工作区] 修改后，被修改的文件出现<img alt="" src="http://www.qudee.com/scv20071110/images/tech/0_2.gif">标志，选择 &#8220;比较差异Diff&#8221; 命令，可以查看该文件与版本仓库中文件具体差异，选择命令后出现对应的差异察看窗口。 <br><br>0.加入(Add)新文件/新文件夹<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/12.gif"><br>&nbsp;&nbsp;想把在开发过程中创建的新文件/文件夹加入到SVN控制之下，可以这样做：选中文件/文件夹（在新文件/文件夹所在父文件夹点击右键），然后在菜单中选择&#8220;添加Add&#8221;命令。不需要受SVN控制的文件请取消钩选。 <br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/13.gif"><br>在把文件或文件夹加入到控制之下后，这些文件或文件夹就会显示为一个Added覆盖<img alt="" src="http://www.qudee.com/scv20071110/images/tech/0_1.gif">图标的样子，接下来必须对[本地工作区] 执行提交commit操作，以便其他团队成员能够看到这些文件或文件夹。<br><br>0.删除、重命名、移动<br>选择要删除（或重命名）的文件/文件夹，点击鼠标右键选择相应命令： <br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/14.gif"><br>&nbsp;&nbsp;如果使用TortoiseSVN的&#8220;删除Delete&#8221;操作删除了一个文件/文件夹，文件就已经从[本地工作区]中删除了，而被&#8220;删除Delete&#8221; 的文件夹将显示为覆盖图标。要恢复被&#8220;删除Delete&#8221;文件/文件夹，只需对他的上级文件夹进行&#8220;SVN还原revert&#8221;操作即可。<br>如果要在[本地工作区]内移动文件，可以使用鼠标来拖拽：<br>&nbsp;&nbsp;&nbsp;&nbsp;1．选中要移动的文件或文件夹。<br>&nbsp;&nbsp;&nbsp;&nbsp;2．用鼠标右键拖拽他们到[本地工作区]中一个新的文件夹。<br>&nbsp;&nbsp;&nbsp;&nbsp;3．松开鼠标右键。<br>&nbsp;&nbsp;&nbsp;&nbsp;4．在跳出的菜单中选择相应命令，如下图： <br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/15.gif"><br>&nbsp;&nbsp;如果一个删除操作不是使用TortoiseSVN的&#8220;删除Delete&#8221;操作完成的，而是就像平常删除文件那样删除的。提交时，对话框窗口还是会显示 这些删除的文件，并提示自己把它们从版本控制下删除。所以如果忘记使用TortoiseSVN&#8220;删除Delete&#8221;操作来删除这些文件，仍可在这里补上。<br><br>0.取消改变(revert)<br>&nbsp;&nbsp;如果要取消对一个文件/文件夹所做的修改，只需用鼠标右键单击该文件/文件夹，选择TortoiseSVN子菜单中的&#8220;SVN还原revert&#8221;命 令，在操作窗口中会显示需要还原的文件/文件夹，勾选文件/文件夹后按下&#8220;确定OK&#8221;按钮即可。注意这里所做的取消修改只能返回到该文件/文件夹上次&#8220;更 新Update&#8221;后的状态。<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/16.gif"><br><br>0.修订日志窗口<br>&nbsp;&nbsp;每一次修改和提交，都应该做好日志记录。这样开发过程中就有了一个详细的记录，以后便可找出每一个修改是如何修改以及为什么这样修改的。 日志对话框会显示所有日志信息。显示分成3个部分：<br>&nbsp;&nbsp;&nbsp;&nbsp;1.最上面部分显示的是所有被提交的版本列表。显示有日期时间、提交者、修订版本号和日志信息的前面一部分。用蓝色显示的行表示有某些文件被复制到了这个版本。（也许是从一个分支来的）<br>&nbsp;&nbsp;&nbsp;&nbsp;2.中间部分显示的是选中版本的所有日志信息。<br>&nbsp;&nbsp;&nbsp;&nbsp;3.底部显示的是选中版本所做修改的文件和文件夹列表。<br>还不仅仅是这些，对话框中还提供了很多的菜单命令可以使用。<br><img alt="" src="http://www.qudee.com/scv20071110/images/tech/17.gif"><br><br>0.文件库浏览器<br>&nbsp;&nbsp;选择&#8220;文件库浏览器&#8221;菜单，就可以打开Subversion服务器上版本库的结构，并可以对版本库中的文件/文件夹进行操作，如下图： <br><img style="WIDTH: 552px; HEIGHT: 433px" height=433 alt="" src="http://www.qudee.com/scv20071110/images/tech/18.gif" width=552></p>
</div>
<img src ="http://www.cppblog.com/niewenlong/aggbug/65284.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-28 10:49 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/28/65284.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开始使用svn(subversion) </title><link>http://www.cppblog.com/niewenlong/archive/2008/10/28/65283.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Tue, 28 Oct 2008 02:41:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/28/65283.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/65283.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2008/10/28/65283.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/65283.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/65283.html</trackback:ping><description><![CDATA[<span style="FONT-FAMILY: 幼圆">&nbsp;&nbsp;&nbsp; windows下的客户端推荐使用TortoiseSVN。TortoiseSVN是windows平台下最经典的SVN客户端,操作及其简便直观,直接跟windows系统结合,通过文件/文件夹右键菜单方式进行管理您的项目.不过我喜欢用它的命令行，因为以前用CVS的时候就是用命令行，而SVN的命令行方式几乎和CVS是一样的，所以很快上手了。<br><br>&nbsp;&nbsp;&nbsp; 从</span><a title=http://subversion.tigris.org style="FONT-FAMILY: 幼圆" href="http://subversion.tigris.org/">http://subversion.tigris.org</a><span style="FONT-FAMILY: 幼圆">获取subversion for windows的版本，安装之后就有了svn.exe这个基于命令行的客户端工具。当然服务器端的程序也有了，这里就不关心如何配置SVN服务了。安装程序把svn.exe的路径加入了path环境变量,我们已经可以在命令行中直接输入svn就可以使用了。</span><br><br><span style="FONT-FAMILY: 幼圆">如果你不知道命令怎么用svn命令,可通过如下方式查询：<br>svn help<br>知道了子命令，但是不知道子命令的用法，还可以查询：<br>svn help ci <br><br>开发人员常用命令<br><br>导入项目<br>svn import http://svn.chinasvn.com:82/pthread --message "Start project"<br><br>导出项目<br>svn checkout http://svn.chinasvn.com:82/pthread<br><br>采用 export 的方式来导出一份&#8220;干净&#8221;的项目<br>svn export http://svn.chinasvn.com:82/pthread pthread<br><br>为失败的事务清场<br>svn cleanup<br><br>在本地进行代码修改，检查修改状态<br>svn status -v<br>svn diff<br><br>更新(update)服务器数据到本地<br>svn update directory<br>svn update file<br><br>增加(add)本地数据到服务器<br>svn add file.c<br>svn add dir<br><br>对文件进行改名和删除<br>svn mv b.c bb.c<br>svn rm d.c<br><br>提交(commit)本地文档到服务器<br>svn commit<br>svn ci<br>svn ci -m "commit"<br><br>查看日志<br>svn log directory<br>svn log file<br><br>相关的一些东西：<br>1、在本地文件中，每个目录下都有一个.svn文件夹(属性为隐藏)，保存了相关的信息。<br>2、注册环境变量SVN_EDITOR为"E:\Program Files\Vim\vim71\gvim.exe"，结果在svn ci的时候，出现错误:<br><br>'E:\Program' 不是内部或外部命令，也不是可运行的程序<br>或批处理文件。<br>svn: 提交失败(细节如下):<br>svn: system('E:\Program Files\Vim\vim71\gvim.exe svn-commit.tmp') 返回 1<br><br>把SVN_EDITOR改为"gvim.exe"，并且在path中添加路径"E:\Program Files\Vim\vim71\",这样就可以在提交的时候用vim编写注释了。<br><br>附:<br>提供免费SVN服务的网站:<br></span><a title=http://www.svnhost.cn/ href="http://www.svnhost.cn/"><span style="FONT-FAMILY: 幼圆">http://www.svnhost.cn/</span></a><span style="FONT-FAMILY: 幼圆">(推荐)<br></span><a title=http://www.chinasvn.com href="http://www.chinasvn.com/"><span style="FONT-FAMILY: 幼圆">http://www.chinasvn.com</span></a><br><a title=http://www.javaforge.com href="http://www.javaforge.com/"><span style="FONT-FAMILY: 幼圆">http://www.javaforge.com</span></a><br><a title=http://unfuddle.com href="http://unfuddle.com/"><span style="FONT-FAMILY: 幼圆">http://unfuddle.com</span></a><br><a title=http://svn.coollittlethings.com/index.php href="http://svn.coollittlethings.com/index.php"><span style="FONT-FAMILY: 幼圆">http://svn.coollittlethings.com/index.php</span></a><span style="FONT-FAMILY: 幼圆">(针对开源免费，针对私人项目收费)<br></span>
<img src ="http://www.cppblog.com/niewenlong/aggbug/65283.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-28 10:41 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/28/65283.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SVN-Subversion快速指南</title><link>http://www.cppblog.com/niewenlong/archive/2008/10/28/65282.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Tue, 28 Oct 2008 02:32:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/10/28/65282.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/65282.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2008/10/28/65282.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/65282.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/65282.html</trackback:ping><description><![CDATA[<p class=cc-lisence style="FONT-SIZE: 14pt; LINE-HEIGHT: 180%; FONT-FAMILY: 幼圆" minmax_bound="true"><a href="http://creativecommons.org/licenses/by/3.0/deed.zh" target=_blank minmax_bound="true"><u><font color=#0000ff>版权声明</font></u></a>：转载时请以超链接形式标明文章原始出处和作者信息及<a href="http://bangzhuzhongxin.blogbus.com/logs/11205960.html" target=_blank minmax_bound="true"><font color=#0000ff><u>本声明</u></font></a><br minmax_bound="true"><a href="http://egeho123.blogbus.com/logs/18119163.html" minmax_bound="true"><u><font color=#810081>http://egeho123.blogbus.com/logs/18119163.html</font></u></a><br minmax_bound="true"><br minmax_bound="true"></p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">Subversion快速指南</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">Subversion（简写为SVN）作为开源社区贡献的新一代版本控制系统，已经得到越来越广泛的使用。我用过CVS（Concurent Version System，SVN的前身）和微软的VSS（Visual SourceSafe），相比之下，SVN具有更强大的功能和更简单的操作特性。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">网上已有一些文章介绍SVN的安装和使用，不过我在第一次配置时仍然遇到了几个问题。这里，我按照自己的思路来进行讲解，以期对那些初次使用SVN并且对一些问题存在疑问的朋友有所帮助。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">1. SVN简介</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">光说SVN好，那SVN究竟有什么优点呢？在SVN的手册里有着详细的说明，下面简单介绍几个重要方面：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">1) 基于目录的版本控制</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">传统的CVS或VSS都是基于单个文件进行版本控制的，这实际上满足不了实际需求，因为在实际应用中，我们都希望按照项目或者工程进行管理，例如假设我们想要取出某个历史时间点的整个项目文件，那么基于文件的版本控制系统就存在弊端，只能单个单个文件的处理。而SVN则能很方便的做到这一点，你可以随意的取出任何一个文件、任何一个目录的任何一个历史版本。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN还允许对文件和目录进行增加、删除以及复制和重命名等操作，这些都会被记录到历史信息中，实现真正的版本控制功能。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">2) 原子提交</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN里的每次操作都是原子的，要么全部成功，要么全部失败。假设你要提交多个文件，如果有一个存在冲突，那么其它修改都不会被提交。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">3) 高效的分支（branching）与标签（tagging）功能</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">先说标签功能，通俗的讲，标签就是某个时间点的快照（snapshot），我们可以在项目进行到一些重要的里程碑之时为之建立标签，这样可以方便以后随时取出这些历史版本。我想你会有一个疑问：SVN不是本身就有随意取出任何一个历史版本的功能吗？是的，标签的作用主要是为了给这些特定的历史版本取一个友好的名字，以方便使用和维护。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">分支则是用于创建多个并行的工作线，比如，当我们的一个项目需要为某个用户提供一些特殊的功能时，那么就可以为之创建一个分支，这样能够保正大部分代码的共用，也使得整个项目变得容易维护和管理。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN对于分支和标签的实现都是一样的，并且采用了与Unix/Linux硬链接（Hard-Link）类似的机制，即是说，当我们创建分支或标签时，SVN并不会立即为之创建一份拷贝，而是创建一个链接，只有当这些文件以后被修改时才会真正产生一份副本。这种&#8220;缓式拷贝&#8221;方法是一种常见的优化方法，能够有效的节约空间。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">那分支和标签又有什么不同呢？不同之处仅仅在于其&#8220;约定成俗&#8221;的含义，标签意味着你不会再对其进行修改，而分支意味着你会对它进行开发。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">4) 多种访问方式</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN提供了一个抽象的网络访问层，可以通过不同的协议来对其进行访问。首先，SVN提供了自定义的svn协议访问方式，通过形如svn://host/repository的URL就能使用。再有，SVN还提供了与Apache Web服务器相集成的功能，这样，我们就可以通过<a href="http://host/repository" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://host/repository</u></font></a>的方式来访问SVN了。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">5) 对二进制文件的支持</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">CVS虽然对二进制文件也有支持，但实现得并不完善，你或许遇到过文本文件里有中文字符而被认为是二进制文件的事情，SVN则提供了对二进制文件全面的支持，使得非文本文件也能跟文本文件一样进行良好的版本控制。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">6) Windows下与资源管理器集成的客户端：TortoiseSVN</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN本身只提供命令行的操作方式，TortoiseSVN是第三方开发的图形化界面，它的出现使Windows下的版本管理变得非常方便。不过，由于是嵌入到资源管理器中，它可能会影响系统的速度——微乎其微，你可以自己评测一下。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">7) 平台无关</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN秉承了开源软件的一贯优点，无论是Windows还是Linux平台，都可以相互访问SVN服务器。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">如果你过去是VSS用户，那么这里还要提一点，与VSS相比，SVN还有一个理念不一样，VSS将版本冲突控制放在操作之前，你要操作某个项目必须先执行CheckOut以进行锁定、防止他人同时修改。SVN提供了同样的Lock功能，但通常情况下，我们只需各自独立的进行修改而无需锁定项目，如果有冲突在提交的时候再做处理，也就是说，SVN是将冲突控制放在操作之后、提交之时。也许你会觉得VSS更合理，但实际情况却相反，因为在我们的实际使用中经常发生有人将整个项目CheckOut后忘了CheckIn，或者未选择Recursive忘了将子目录中的文件CheckIn，这就让其他人无法修改，于是不得不人为的通知其本人，非常麻烦。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">2. SVN服务器搭建</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">本节是针对管理员写的，普通用户可以跳过本节。我这里只以Windows上的安装为例，Linux上可按类似方式进行（有些配置参数会存在差别，具体参考帮助手册）。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">1) 安装SVN服务器</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">a. 下载</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN的官方网站为<a href="http://subversion.tigris.org/" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://subversion.tigris.org/</u></font></a>，当前最新版本为1.4.2。Windows下的二进制安装包分为两种，一种是以setup结尾的安装文件，另一种是普通的压缩包文件，setup文件会自动注册一些信息，比如环境变量以及服务等，这些都是可以自己手动实现的。在我写这篇文章时，官方网站上就只有普通二进制文件，估计setup文件稍晚些时候会出来。特别注意，下载时要详细阅读注意事项，看清与之配套的软件的版本号，避免出现问题。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">我选择的版本为svn-win32-1.4.2.zip</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">b. 安装</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">将svn-win32-1.4.2.zip解压缩到安装目录下，我选择的是C:/Program Files/Subversion，如果是setup文件，直接运行安装文件即可。对于压缩包，我们可以将bin路径添加到系统环境变量中，以方便操作。可以看到，bin目录下主要有如下几个文件：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">svnadmin：仓库管理工具，包括创建、修复和备份等操作。<br minmax_bound="true">svnlook：仓库查看工具，包括信息、日志和锁定状态等内容，不会造成仓库的改动。<br minmax_bound="true">svnserve：svn服务程序，允许通过svn网络协议来访问仓库。<br minmax_bound="true">svn：SVN客户端，用于访问仓库，对项目进行版本管理。<br minmax_bound="true">svnversion：客户端工具，用于查看本地拷贝的修订信息。<br minmax_bound="true">c. 创建仓库（Repository）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN是以仓库为版本控制单位的，一个SVN服务器可以管理多个仓库，每个仓库拥有独立的修订号（REVISION），仓库中的任何一次更新都会带来修订号的递增。你可以根据需要选择建立一个或者多个仓库，这里，我以创建多个仓库为例子，假设我们将仓库都放到D:/SVN_REPOS目录下，下面的命令将会在该目录下创建一个Test仓库：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">svnadmin create D:/SVN_REPOS/Test <br minmax_bound="true">如果创建成功，D:/SVN_REPOS/下将会多一个Test目录。 <br minmax_bound="true">2) 搭建svnserve访问方式</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">svn和http是两种并列的访问方式，你可以选择其中一种，也可以都采用。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">a. 注册服务</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">为了让SVN服务程序每次开机后自动运行，我们需要将其注册为服务。在控制台中执行如下命令：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">sc create svnservice binPath= "\"C:\Program Files\Subversion\bin\svnserve.exe\" --service -r D:/SVN_REPOS" start= auto <br minmax_bound="true">注意，上述命令均在一行中。sc.exe是Windows 2000以后系统自带的一个工具，2000下没有，可以从XP上拷过来。svnservice为服务名称，后面的参数格式有严格要求，等号前面没有空格而后面有。binPath本身带有多个参数，因此用引号括起来，而由于路径里面又有空格，因此又加上了一层引号。 --service和-r均为svnserve.exe的参数，前者要求它作为服务运行，后者指明了仓库的根路径（多仓库为仓库的父目录）。 <br minmax_bound="true">带安装包的SVN会自动注册服务，这时我们可能需要修改-r参数，命令如下：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">sc config svnservice binPath= "\"C:\Program Files\Subversion\bin\svnserve.exe\" --service -r D:/SVN_REPOS"<br minmax_bound="true">b. 访问</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">注册完后，通过运行sc start svnservice或者服务管理器（service.msc）启动服务。<br minmax_bound="true">接下来，我们就可以通过下面的命令来测试系统是否工作正常：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">svn info svn://localhost/Test<br minmax_bound="true">如果正确的显示出仓库的相关信息，那么就大功告成了，否则请检查服务的参数是否配置正确，比如，如果未在服务参数中指定正确的-r值，就会得到如下错误：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">No repository found in 'svn://localhost/Test'<br minmax_bound="true">如果安装了TortoiseSVN，则可以直接在浏览器中输入svn://localhost/Test，这样会调出TortoiseSVN的Repos-Browser。到此，你就可以通过TortoiseSVN来导入工程进行版本管理了（参见后文）。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">c. 权限配置</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">在进行权限配置前，所有的用户都能进行任何操作，在很多情况下是不允许的。在创建仓库时，仓库目录下都会生成好几个文件夹，其中conf里面存储的是配置信息，包括三个文件：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">authz：访问权限配置<br minmax_bound="true">passwd：用户名和密码配置<br minmax_bound="true">svnserve.conf：基本配置信息<br minmax_bound="true">先配置svnserve.conf，将里面几项配置前的注释去掉，最后的内容如下：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[general]<br minmax_bound="true">anon-access = read<br minmax_bound="true">auth-access = write<br minmax_bound="true">password-db = passwd<br minmax_bound="true">authz-db = authz <br minmax_bound="true">这些参数的含义文件里都有详细说明，其中，anon-access和auth-access分别是对匿名用户以及认证用户的访问控制，password-db指明用户密码文件路径，authz-db指明权限配置文件路径。另外还有一个参数realm用于指明仓库所属的认证域，默认情况下每个仓库位于不同的域（每个仓库有一个唯一的uuid），因此我们可以不设置该项，除非多个仓库需要共用同一份passwd配置。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">passwd文件的配置很简单，格式如下（等号前面为用户名，后面为密码）：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[users]<br minmax_bound="true">harry = 123<br minmax_bound="true">sally = 123<br minmax_bound="true">guest = 123 <br minmax_bound="true">authz则可以创建用户组并精确配置某个用户或用户组对某个文件或目录的访问权限，下面是一个例子：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[groups]<br minmax_bound="true">harry_and_sally = harry,sally <br minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[/]<br minmax_bound="true">* = r</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[/project1]<br minmax_bound="true">* =<br minmax_bound="true">harry = rw<br minmax_bound="true">sally = r</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[/project1/foo]<br minmax_bound="true">sally = </p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[/project2]<br minmax_bound="true">@harry_and_sally = rw<br minmax_bound="true">guest = r</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">文件内容其实很简单易懂，groups用于定义用户组，后面便是对资源的具体访问控制，/表示仓库根目录，*表示所有用户，用户组前面需加上@符号，r表示可读，w表示可写，等号右边为空则表示没有权限。注意对于目录结构，当用户访问某个资源时，SVN会先看有没有直接针对该资源的访问控制，如果没有找到，则会继承上一级目录的访问权限，如此递推。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">再提一点，当我们有多个仓库时，我们会发现这些仓库的用户帐号在大多数情况下都是相同的，因此，我们可以将passwd文件放到公共的地方，然后将所有仓库的password-db配置都指向该文件。相应的，authz-db也可以共用一个文件，不过需要在配置具体的访问控制时指明所属的仓库，如下：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[/]<br minmax_bound="true">* = r <br minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[repos1:/project1]<br minmax_bound="true">* = r<br minmax_bound="true">harry = rw</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">[repos2:/project1]<br minmax_bound="true">* = r<br minmax_bound="true">sally = rw</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">上述配置表明，所有人对所有仓库的根目录都有读权限，但只有harry对仓库repos1里的project1有读写权限，只有sally对仓库repos2里的project1有读写权限。 <br minmax_bound="true">3) 搭建HTTP访问方式</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN可以通过Apache实现Web访问方式，但这不是必需的，除非你有此需求。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">a) 下载</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">Apache的官方网站为<a href="http://www.apache.org/" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://www.apache.org/</u></font></a>，注意不要使用最新的2.2.x，而要选择2.0.x，这一点在SVN官方网站上有特别说明，当初我就没有注意到这一点，而导致Apache2.2启动时无法加载SVN的模块，出现&#8220;perhaps this is not an Apache module DSO&#8221;错误。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">我下载的版本为apache_2.0.59-win32-x86-no_ssl.msi</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">b) 安装和注册</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">执行Apache安装程序。由于2.0的版本不会自动注册为服务，因此我们需要手工处理。运行cmd.exe，进入apache安装目录下的bin文件夹，执行如下命令即可：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">apache -k install<br minmax_bound="true">更多的命令可以通过apache help查看。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">注册完后，就可以通过系统托盘里的Apache Monitor来启动服务。如果80端口未被占用，那么服务器应正常启动，通过<a href="http://127.0.0.1/" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://127.0.0.1</u></font></a>就能看到Apache的测试页面。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">c) 配置</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">Apache是通过conf目录中的httpd.conf文件进行配置的，比如，默认的监听端口为80，在文件中搜索Listen 80，将80改成你所需的其它端口即可。配置完后必须重起Apache才能生效。更多关于Apache的配置说明请参见其帮助手册或google之。下面网站为帮助手册的中文版本。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">为了让Apache支持SVN，比如增加一些配置项，一个典型的配置如下：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true"># 加载mod_dav模块，它是对WebDAV（Web-based Distributed Authoring and Versioning）协议的支持，由Apache自带<br minmax_bound="true">LoadModule dav_module modules/mod_dav.so</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true"># 加载mod_dav_svn模块，它与mod_dav通信，使Apache支持SVN，它位于SVN的bin目录下。<br minmax_bound="true">LoadModule dav_svn_module "D:/Program Files/Subversion/bin/mod_dav_svn.so"</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true"># 加载mod_authz_svn模块，用于进行权限管理<br minmax_bound="true">LoadModule authz_svn_module "D:/Program Files/Subversion/bin/mod_authz_svn.so"</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true"># 配置SVN的访问路径以及相关相关参数<br minmax_bound="true">&lt;Location /svn/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 通过<a href="http://host/svn/" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://HOST/svn/</u></font></a>访问SVN服务器<br minmax_bound="true">&nbsp;&nbsp;&nbsp; DAV svn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 必需<br minmax_bound="true">&nbsp;&nbsp;&nbsp; SVNParentPath D:/SVN_REPOS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 说明D:/SVN_REPOS下的所有目录均为仓库<br minmax_bound="true">&nbsp;&nbsp;&nbsp; SVNListParentPath on&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 在网页中列出D:/SVN_REPOS下的所有仓库<br minmax_bound="true">&nbsp;&nbsp;&nbsp; <br minmax_bound="true">&nbsp;&nbsp;&nbsp; AuthType Basic&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 基本的用户名密码验证方式<br minmax_bound="true">&nbsp;&nbsp;&nbsp; AuthName "SVN REPOS"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 认证名称，作提示用<br minmax_bound="true">&nbsp;&nbsp;&nbsp; AuthUserFile D:/SVN_REPOS/users&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 用户名密码文件<br minmax_bound="true">&nbsp;&nbsp;&nbsp; AuthzSVNAccessFile D:/SVN_REPOS/authz&nbsp;&nbsp;&nbsp; # 权限控制文件</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">&nbsp;&nbsp;&nbsp; Require valid-user&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 只有通过认证才能访问网页<br minmax_bound="true">&lt;/Location&gt;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true"># 重定向处理，用于将<a href="http://host/svn" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://HOST/svn</u></font></a>地址重定向为<a href="http://host/svn/" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://HOST/svn/</u></font></a><br minmax_bound="true">RedirectMatch ^(/svn)＄ ＄1/</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">下面对几个重要的地方作以说明：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">i. 网上很多文章提到将mod_dav_svn.so和mod_authz_svn.so两个文件直接拷贝到Apache的modules目录下，当初我按照这种方法做时结果在一台Windows 2000 Server上无法启动Apache服务，为此折腾了半天。后来才明白，这些模块文件其实就是一些动态链接库，它需要依赖SVN的bin目录下的其它几个dll文件（可以把后缀改为dll，然后通过VC带的depends查看其依赖关系），因此如果没有设置环境变量，那么Apache加载这些模块时就会失败，当然也可以把所有依赖文件（主要是libdb43.dll ）拷贝过去。实际上，我们只需要通过绝对路径来引用这些模块即可，这样SVN升级后也不用再次拷贝。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">ii. URL的访问路径为/svn/而不是/svn，因为后者可能有问题，导致通过<a href="http://host/svn" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://HOST/svn</u></font></a>访问出现如下错误信息</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">iii. SVNParentPath用于有多个仓库的情况，如果只有单个仓库，可以直接用SVNPath指明仓库路径。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">iv. AuthUserFile指明用户名密码文件，但它与前面提到的SVN仓库下的passwd文件不是同一个文件，AuthUserFile是Apache的认证文件格式，二者的区别主要是用户名和密码的分割符不同，passwd是等号，这里的users是冒号，当初我就是把它们当成一个文件而造成客户端无法访问（为什么SVN不把passwd的格式定义成和AuthUserFile的一样呢？这样二者可以共用一个文件）。如果要对密码加密，那么users文件需通过Apache附带的htpasswd工具生成，实际上我们也可直接采用明文方式。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">v. 权限控制文件AuthzSVNAccessFile与前面SVN里的authz一样，因此可以共用。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">4) 其它管理功能</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">a. 备份</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">b. 修复</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">&nbsp;</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">3. SVN客户端使用</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">本节针对客户端用户，主要介绍一些常用的操作方法。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">1) 客户端安装</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">客户端可以采用命令行方式，也可以采用TortoiseSVN图形化方式，个人认为还是后者方便些。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">TortoiseSVN从<a href="http://tortoisesvn.tigris.org/" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://tortoisesvn.tigris.org/</u></font></a>上获取，注意版本应与服务器保持一致。如果是命令行方式的话，那么从<a href="http://subversion.tigris.org/" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://subversion.tigris.org/</u></font></a>下载一个SVN二进制包就行了，此处不多讲。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">TortoiseSVN属于图形化的客户端软件，其实前面的SVN安装包里已经含有客户端程序，只不过是命令行方式的，你可以根据需要选择是否安装。TortoiseSVN的官方网站为<a href="http://tortoisesvn.tigris.org/" minmax_bound="true"><font color=#005880 minmax_bound="true"><u>http://tortoisesvn.tigris.org/</u></font></a>，同样，注意选择与SVN服务器配套的版本。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">我这里使用的版本为TortoiseSVN-1.4.0.7501-win32-svn-1.4.0.msi</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">安装完后，会提示重起机器，实际上不用重起就能直接使用，只不过重起后会更新SVN文件图标的显示。下图是SVN工作区的右键菜单内容：</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true"><br minmax_bound="true">2) 主要操作</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">TortoiseSVN使用起来很简单，所有操作都通过右键菜单来完成。命令内容也很直观，而且有非常详细的帮助手册，这里只简单的介绍一下。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">a) 导入项目（Import）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">首先要把需要进行版本管理的工程（目录）整理好，去掉不必要的文件，比如编译器生成的临时文件。然后在最上层文件夹上单击右键，选择&#8220;TortoiseSVN -&gt; Import...&#8221;，输入要存放的SVN服务器路径，确认即可。这样就将本地的项目导入到了服务器上。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">命令行：svn import [PATH] URL</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">b) 检出项目（Checkout）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">项目初次导入成功后，刚才本地的内容就没有用了，我们需要建立一个新的工作区，重新从SVN服务器下载受控的项目文件，执行&#8220;TortoiseSVN -&gt; Checkout...&#8221;，选择或者输入项目的URL，确认即可，以后的工作都应在这个工作区里进行。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">默认是获取项目的最新版本（HEAD），如果要获取历史版本，指定相应的修订号（Revision）即可。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">命令行：svn checkout URL[@REV]... [PATH]</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">c) 更新与提交（Update and Commit）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">他人修改了项目，我们需要从服务器下载最新版本，这通过&#8220;SVN Update&#8221;右键菜单实现。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">命令行：svn update [PATH...]</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">如果是自己本地作了修改，则应及时将修改更新到服务器上去，这通过&#8220;SVN Commit...&#8221;实现。一个好的习惯是每次提交都应注明修改内容，以方便日后查证。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">命令行：svn commit [PATH...]</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">d) 增加和删除文件（Add and Delete）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">如果我们要向一个受控项目中添加新文件或文件夹，只需在目标上执行&#8220;TortoiseSVN -&gt; Add&#8221;操作。注意，这里只是本地添加，要提交到服务器，还必须执行Commit才行。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">命令行：svn add PATH...</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">同样，要删除受控文件或文件夹只需执行&#8220;TortoiseSVN -&gt; Delete&#8221;操作。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">命令行：svn delete PATH/URL...</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">TortoiseSVN还提供了一个重命名操作&#8220;TortoiseSVN -&gt; Rename&#8221;，这其实是添加和删除的组合。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">e) 撤销操作（Revert）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">有时候，我们可能进行了错误的修改或者增加和删除，只要未进行提交，我们都可以通过&#8220;TortoiseSVN -&gt; Revert&#8221;命令来撤销本地的所有更改。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">命令行：svn revert PATH...</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">f) 查看信息</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">SVN提供了几种信息查看方式，其中Show log用于显示每次版本变更的日志信息，Repo-brower是仓库浏览器，类似于资源管理器，Revision graph则以图形化的方式让我们很直观的看到版本的变更情况，尤其是对于分支和标签管理很有帮助。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">3) 其它操作</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">a) 冲突解决（Resolved）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">如果我们本地进行了修改，而别人又把他的修改提交到了服务器上，这时我们执行Update就可能出现冲突（Conflict）。Resolved的作用不是解决冲突，它不进行任何合并，而是忽略掉他人的修改，允许我们将自己的版本提交到服务器上。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">简单的说，Revent是撤销本地修改，而Resolved是保留本地修改。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">b) 清除异常状态（Cleanup）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">如果在执行某个命令的时候出现异常，比如服务器突然挂了，本地的工作区就会处于一种异常状态，通过Cleanup能够清除这种状态，使工作区不受到影响。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">c) 锁定（Get lock）和解锁（Release lock）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">冲突都是由于不同的开发人员同时修改了同一份文件造成的，因此，为了避免这种情况，我们可以强行锁定自己要修改的内容，这样其他人在我们解锁前就无法提交其修改。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">d) 分支和标签（Branch/tag）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">本文最开始就有说明，分支的目的是为了创建并行的工作线，标签的作用是为了保存项目某个版本的快照。二者在实现上却是一样的，都是通过Branch/tag命令执行。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">e) 导出（Export）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">为了实现版本管理，SVN会在工作区的每个目录下都生成一个隐藏的.svn文件夹，而我们有时却希望得到一个干净的没有.svn文件夹的项目结构，比如发布软件时，这种情况下就可以使用Export功能。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">f) 重定向（Relocate）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">有时候，SVN服务器的IP地址可能会发生变动，如果遇到这种情况，我们每个人的本地工作区都要重新下载吗？不用，只需通过Relocate重新配置一下本地工作区所对应的服务器地址就可以。</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">g) 补丁管理（patch）</p>
<p style="FONT-SIZE: 14pt; FONT-FAMILY: 幼圆" minmax_bound="true">不要被patch的名称迷惑，实际上它不属于SVN版本管理的范畴。这里所谓的patch是指那些对项目没有写权限（Commit）的人所作的修改，通过&#8220;TortoiseSVN -&gt; Create Patch&#8221;生成，然后他们采用电子邮件等方式将patch发给项目管理员，由管理员执行&#8220;TortoiseSVN -&gt; Apply Patch&#8221;并确认修改内容后再进行提交。该功能主要用于开源项目的管理。</p>
<img src ="http://www.cppblog.com/niewenlong/aggbug/65282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-10-28 10:32 <a href="http://www.cppblog.com/niewenlong/archive/2008/10/28/65282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC++大杂烩</title><link>http://www.cppblog.com/niewenlong/archive/2008/08/28/60279.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Thu, 28 Aug 2008 08:48:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/08/28/60279.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/60279.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2008/08/28/60279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/60279.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/60279.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如何获取系统日期CTime tm = CTime :: GetCurrentTime();CString strTime = tm.Format(_TEXT(&#8220;%Y-%M-%d %H:%M:%S));MessageBox(strTime);&nbsp;2.&nbsp;&nbsp...&nbsp;&nbsp;<a href='http://www.cppblog.com/niewenlong/archive/2008/08/28/60279.html'>阅读全文</a><img src ="http://www.cppblog.com/niewenlong/aggbug/60279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-08-28 16:48 <a href="http://www.cppblog.com/niewenlong/archive/2008/08/28/60279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Mysql日期和时间函数不求人</title><link>http://www.cppblog.com/niewenlong/archive/2008/08/15/58900.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Thu, 14 Aug 2008 16:28:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/08/15/58900.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/58900.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2008/08/15/58900.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/58900.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/58900.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">对于每个类型拥有的值范围以及并且指定日期何时间值的有效格式的描述见7.3.6 日期和时间类型。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">这里是一个使用日期函数的例子。下面的查询选择了所有记录，其date_col的值是在最后30天以内：&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">mysql&gt; SELECT something FROM table&nbsp; <br>WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) &lt;= 30;&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">DAYOFWEEK(date)&nbsp; <br>返回日期date的星期索引(1=星期天，2=星期一, &#8230;&#8230;7=星期六)。这些索引值对应于ODBC标准。&nbsp; <br>mysql&gt; select DAYOFWEEK('1998-02-03');&nbsp; <br>-&gt; 3&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">WEEKDAY(date)&nbsp; <br>返回date的星期索引(0=星期一，1=星期二, &#8230;&#8230;6= 星期天)。&nbsp; <br>mysql&gt; select WEEKDAY('1997-10-04 22:23:00');&nbsp; <br>-&gt; 5&nbsp; <br>mysql&gt; select WEEKDAY('1997-11-05');&nbsp; <br>-&gt; 2&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">DAYOFMONTH(date)&nbsp; <br>返回date的月份中日期，在1到31范围内。&nbsp; <br>mysql&gt; select DAYOFMONTH('1998-02-03');&nbsp; <br>-&gt; 3&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">DAYOFYEAR(date)&nbsp; <br>返回date在一年中的日数, 在1到366范围内。&nbsp; <br>mysql&gt; select DAYOFYEAR('1998-02-03');&nbsp; <br>-&gt; 34&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">MONTH(date)&nbsp; <br>返回date的月份，范围1到12。&nbsp; <br>mysql&gt; select MONTH('1998-02-03');&nbsp; <br>-&gt; 2&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">DAYNAME(date)&nbsp; <br>返回date的星期名字。&nbsp; <br>mysql&gt; select DAYNAME("1998-02-05");&nbsp; <br>-&gt; 'Thursday'&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">MONTHNAME(date)&nbsp; <br>返回date的月份名字。&nbsp; <br>mysql&gt; select MONTHNAME("1998-02-05");&nbsp; <br>-&gt; 'February'&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">QUARTER(date)&nbsp; <br>返回date一年中的季度，范围1到4。&nbsp; <br>mysql&gt; select QUARTER('98-04-01');&nbsp; <br>-&gt; 2&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">WEEK(date)&nbsp; <br>　&nbsp; <br>WEEK(date,first)&nbsp; <br>对于星期天是一周的第一天的地方，有一个单个参数，返回date的周数，范围在0到52。2个参数形式WEEK()允许 <br>你指定星期是否开始于星期天或星期一。如果第二个参数是0，星期从星期天开始，如果第二个参数是1， <br>从星期一开始。&nbsp; <br>mysql&gt; select WEEK('1998-02-20');&nbsp; <br>-&gt; 7&nbsp; <br>mysql&gt; select WEEK('1998-02-20',0);&nbsp; <br>-&gt; 7&nbsp; <br>mysql&gt; select WEEK('1998-02-20',1);&nbsp; <br>-&gt; 8&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">YEAR(date)&nbsp; <br>返回date的年份，范围在1000到9999。&nbsp; <br>mysql&gt; select YEAR('98-02-03');&nbsp; <br>-&gt; 1998&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">HOUR(time)&nbsp; <br>返回time的小时，范围是0到23。&nbsp; <br>mysql&gt; select HOUR('10:05:03');&nbsp; <br>-&gt; 10&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">MINUTE(time)&nbsp; <br>返回time的分钟，范围是0到59。&nbsp; <br>mysql&gt; select MINUTE('98-02-03 10:05:03');&nbsp; <br>-&gt; 5&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">SECOND(time)&nbsp; <br>回来time的秒数，范围是0到59。&nbsp; <br>mysql&gt; select SECOND('10:05:03');&nbsp; <br>-&gt; 3&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">PERIOD_ADD(P,N)&nbsp; <br>增加N个月到阶段P（以格式YYMM或YYYYMM)。以格式YYYYMM返回值。注意阶段参数P不是日期值。&nbsp; <br>mysql&gt; select PERIOD_ADD(9801,2);&nbsp; <br>-&gt; 199803&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">PERIOD_DIFF(P1,P2)&nbsp; <br>返回在时期P1和P2之间月数，P1和P2应该以格式YYMM或YYYYMM。注意，时期参数P1和P2不是日期值。&nbsp; <br>mysql&gt; select PERIOD_DIFF(9802,199703);&nbsp; <br>-&gt; 11&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">DATE_ADD(date,INTERVAL expr type)&nbsp; <br>　&nbsp; <br>DATE_SUB(date,INTERVAL expr type)&nbsp; <br>　&nbsp; <br>ADDDATE(date,INTERVAL expr type)&nbsp; <br>　&nbsp; <br>SUBDATE(date,INTERVAL expr type)&nbsp; <br>这些功能执行日期运算。对于MySQL 3.22，他们是新的。ADDDATE()和SUBDATE()是DATE_ADD()和DATE_SUB()的同义词。 <br>在MySQL 3.23中，你可以使用+和-而不是DATE_ADD()和DATE_SUB()。（见例子）date是一个指定开始日期的 <br>DATETIME或DATE值，expr是指定加到开始日期或从开始日期减去的间隔值一个表达式，expr是一个字符串；它可以以 <br>一个&#8220;-&#8221;开始表示负间隔。type是一个关键词，指明表达式应该如何被解释。EXTRACT(type FROM date)函数从日期 <br>中返回&#8220;type&#8221;间隔。下表显示了type和expr参数怎样被关联： type值 含义 期望的expr格式&nbsp; <br>SECOND 秒 SECONDS&nbsp; <br>MINUTE 分钟 MINUTES&nbsp; <br>HOUR 时间 HOURS&nbsp; <br>DAY 天 DAYS&nbsp; <br>MONTH 月 MONTHS&nbsp; <br>YEAR 年 YEARS&nbsp; <br>MINUTE_SECOND 分钟和秒 "MINUTES:SECONDS"&nbsp; <br>HOUR_MINUTE 小时和分钟 "HOURS:MINUTES"&nbsp; <br>DAY_HOUR 天和小时 "DAYS HOURS"&nbsp; <br>YEAR_MONTH 年和月 "YEARS-MONTHS"&nbsp; <br>HOUR_SECOND 小时, 分钟， "HOURS:MINUTES:SECONDS"&nbsp; <br>DAY_MINUTE 天, 小时, 分钟 "DAYS HOURS:MINUTES"&nbsp; <br>DAY_SECOND 天, 小时, 分钟, 秒 "DAYS HOURS:MINUTES:SECONDS"&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">MySQL在expr格式中允许任何标点分隔符。表示显示的是建议的分隔符。如果date参数是一个DATE值并且你的计算仅仅 <br>包含YEAR、MONTH和DAY部分(即，没有时间部分)，结果是一个DATE值。否则结果是一个DATETIME值。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">mysql&gt; SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND;&nbsp; <br>-&gt; 1998-01-01 00:00:00&nbsp; <br>mysql&gt; SELECT INTERVAL 1 DAY + "1997-12-31";&nbsp; <br>-&gt; 1998-01-01&nbsp; <br>mysql&gt; SELECT "1998-01-01" - INTERVAL 1 SECOND;&nbsp; <br>-&gt; 1997-12-31 23:59:59&nbsp; <br>mysql&gt; SELECT DATE_ADD("1997-12-31 23:59:59",&nbsp; <br>INTERVAL 1 SECOND);&nbsp; <br>-&gt; 1998-01-01 00:00:00&nbsp; <br>mysql&gt; SELECT DATE_ADD("1997-12-31 23:59:59",&nbsp; <br>INTERVAL 1 DAY);&nbsp; <br>-&gt; 1998-01-01 23:59:59&nbsp; <br>mysql&gt; SELECT DATE_ADD("1997-12-31 23:59:59",&nbsp; <br>INTERVAL "1:1" MINUTE_SECOND);&nbsp; <br>-&gt; 1998-01-01 00:01:00&nbsp; <br>mysql&gt; SELECT DATE_SUB("1998-01-01 00:00:00",&nbsp; <br>INTERVAL "1 1:1:1" DAY_SECOND);&nbsp; <br>-&gt; 1997-12-30 22:58:59&nbsp; <br>mysql&gt; SELECT DATE_ADD("1998-01-01 00:00:00",&nbsp; <br>INTERVAL "-1 10" DAY_HOUR);&nbsp; <br>-&gt; 1997-12-30 14:00:00&nbsp; <br>mysql&gt; SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY);&nbsp; <br>-&gt; 1997-12-02&nbsp; <br>mysql&gt; SELECT EXTRACT(YEAR FROM "1999-07-02");&nbsp; <br>-&gt; 1999&nbsp; <br>mysql&gt; SELECT EXTRACT(YEAR_MONTH FROM "1999-07-02 01:02:03");&nbsp; <br>-&gt; 199907&nbsp; <br>mysql&gt; SELECT EXTRACT(DAY_MINUTE FROM "1999-07-02 01:02:03");&nbsp; <br>-&gt; 20102&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">如果你指定太短的间隔值(不包括type关键词期望的间隔部分)，MySQL假设你省掉了间隔值的最左面部分。例如， <br>如果你指定一个type是DAY_SECOND，值expr被希望有天、小时、分钟和秒部分。如果你象"1:10"这样指定值， <br>MySQL假设日子和小时部分是丢失的并且值代表分钟和秒。换句话说，"1:10" DAY_SECOND以它等价于"1:10" MINUTE_SECOND <br>的方式解释，这对那MySQL解释TIME值表示经过的时间而非作为一天的时间的方式有二义性。如果你使用确实不正确的日期， <br>结果是NULL。如果你增加MONTH、YEAR_MONTH或YEAR并且结果日期大于新月份的最大值天数，日子在新月用最大的天调整。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">mysql&gt; select DATE_ADD('1998-01-30', Interval 1 month);&nbsp; <br>-&gt; 1998-02-28&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">注意，从前面的例子中词INTERVAL和type关键词不是区分大小写的。&nbsp; <br>TO_DAYS(date)&nbsp; <br>给出一个日期date，返回一个天数(从0年的天数)。&nbsp; <br>mysql&gt; select TO_DAYS(950501);&nbsp; <br>-&gt; 728779&nbsp; <br>mysql&gt; select TO_DAYS('1997-10-07');&nbsp; <br>-&gt; 729669&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">FROM_DAYS(N)&nbsp; <br>给出一个天数N，返回一个DATE值。&nbsp; <br>mysql&gt; select FROM_DAYS(729669);&nbsp; <br>-&gt; '1997-10-07'&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">DATE_FORMAT(date,format)&nbsp; <br>根据format字符串格式化date值。下列修饰符可以被用在format字符串中： %M 月名字(January&#8230;&#8230;December)&nbsp; <br>%W 星期名字(Sunday&#8230;&#8230;Saturday)&nbsp; <br>%D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。）&nbsp; <br>%Y 年, 数字, 4 位&nbsp; <br>%y 年, 数字, 2 位&nbsp; <br>%a 缩写的星期名字(Sun&#8230;&#8230;Sat)&nbsp; <br>%d 月份中的天数, 数字(00&#8230;&#8230;31)&nbsp; <br>%e 月份中的天数, 数字(0&#8230;&#8230;31)&nbsp; <br>%m 月, 数字(01&#8230;&#8230;12)&nbsp; <br>%c 月, 数字(1&#8230;&#8230;12)&nbsp; <br>%b 缩写的月份名字(Jan&#8230;&#8230;Dec)&nbsp; <br>%j 一年中的天数(001&#8230;&#8230;366)&nbsp; <br>%H 小时(00&#8230;&#8230;23)&nbsp; <br>%k 小时(0&#8230;&#8230;23)&nbsp; <br>%h 小时(01&#8230;&#8230;12)&nbsp; <br>%I 小时(01&#8230;&#8230;12)&nbsp; <br>%l 小时(1&#8230;&#8230;12)&nbsp; <br>%i 分钟, 数字(00&#8230;&#8230;59)&nbsp; <br>%r 时间,12 小时(hh:mm:ss [AP]M)&nbsp; <br>%T 时间,24 小时(hh:mm:ss)&nbsp; <br>%S 秒(00&#8230;&#8230;59)&nbsp; <br>%s 秒(00&#8230;&#8230;59)&nbsp; <br>%p AM或PM&nbsp; <br>%w 一个星期中的天数(0=Sunday &#8230;&#8230;6=Saturday ）&nbsp; <br>%U 星期(0&#8230;&#8230;52), 这里星期天是星期的第一天&nbsp; <br>%u 星期(0&#8230;&#8230;52), 这里星期一是星期的第一天&nbsp; <br>%% 一个文字&#8220;%&#8221;。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">所有的其他字符不做解释被复制到结果中。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">mysql&gt; select DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y');&nbsp; <br>-&gt; 'Saturday October 1997'&nbsp; <br>mysql&gt; select DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');&nbsp; <br>-&gt; '22:23:00'&nbsp; <br>mysql&gt; select DATE_FORMAT('1997-10-04 22:23:00',&nbsp; <br>'%D %y %a %d %m %b %j');&nbsp; <br>-&gt; '4th 97 Sat 04 10 Oct 277'&nbsp; <br>mysql&gt; select DATE_FORMAT('1997-10-04 22:23:00',&nbsp; <br>'%H %k %I %r %T %S %w');&nbsp; <br>-&gt; '22 22 10 10:23:00 PM 22:23:00 00 6'&nbsp; <br>MySQL3.23中，在格式修饰符字符前需要%。在MySQL更早的版本中，%是可选的。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">TIME_FORMAT(time,format)&nbsp; <br>这象上面的DATE_FORMAT()函数一样使用，但是format字符串只能包含处理小时、分钟和秒的那些格式修饰符。 <br>其他修饰符产生一个NULL值或0。&nbsp; <br>CURDATE()&nbsp; <br>　&nbsp; <br>CURRENT_DATE&nbsp; <br>以'YYYY-MM-DD'或YYYYMMDD格式返回今天日期值，取决于函数是在一个字符串还是数字上下文被使用。&nbsp; <br>mysql&gt; select CURDATE();&nbsp; <br>-&gt; '1997-12-15'&nbsp; <br>mysql&gt; select CURDATE() + 0;&nbsp; <br>-&gt; 19971215&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">CURTIME()&nbsp; <br>　&nbsp; <br>CURRENT_TIME&nbsp; <br>以'HH:MM:SS'或HHMMSS格式返回当前时间值，取决于函数是在一个字符串还是在数字的上下文被使用。&nbsp; <br>mysql&gt; select CURTIME();&nbsp; <br>-&gt; '23:50:26'&nbsp; <br>mysql&gt; select CURTIME() + 0;&nbsp; <br>-&gt; 235026&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">NOW()&nbsp; <br>　&nbsp; <br>SYSDATE()&nbsp; <br>　&nbsp; <br>CURRENT_TIMESTAMP&nbsp; <br>以'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS格式返回当前的日期和时间，取决于函数是在一个字符串还是在数字的 <br>上下文被使用。&nbsp; <br>mysql&gt; select NOW();&nbsp; <br>-&gt; '1997-12-15 23:50:26'&nbsp; <br>mysql&gt; select NOW() + 0;&nbsp; <br>-&gt; 19971215235026&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">UNIX_TIMESTAMP()&nbsp; <br>　&nbsp; <br>UNIX_TIMESTAMP(date)&nbsp; <br>如果没有参数调用，返回一个Unix时间戳记(从'1970-01-01 00:00:00'GMT开始的秒数)。如果UNIX_TIMESTAMP()用一 <br>个date参数被调用，它返回从'1970-01-01 00:00:00' GMT开始的秒数值。date可以是一个DATE字符串、一个DATETIME <br>字符串、一个TIMESTAMP或以YYMMDD或YYYYMMDD格式的本地时间的一个数字。&nbsp; <br>mysql&gt; select UNIX_TIMESTAMP();&nbsp; <br>-&gt; 882226357&nbsp; <br>mysql&gt; select UNIX_TIMESTAMP('1997-10-04 22:23:00');&nbsp; <br>-&gt; 875996580&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">当UNIX_TIMESTAMP被用于一个TIMESTAMP列，函数将直接接受值，没有隐含的&#8220;string-to-unix-timestamp&#8221;变换。&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">FROM_UNIXTIME(unix_timestamp)&nbsp; <br>以'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS格式返回unix_timestamp参数所表示的值，取决于函数是在一个字符串 <br>还是或数字上下文中被使用。&nbsp; <br>mysql&gt; select FROM_UNIXTIME(875996580);&nbsp; <br>-&gt; '1997-10-04 22:23:00'&nbsp; <br>mysql&gt; select FROM_UNIXTIME(875996580) + 0;&nbsp; <br>-&gt; 19971004222300&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">FROM_UNIXTIME(unix_timestamp,format)&nbsp; <br>返回表示 Unix 时间标记的一个字符串，根据format字符串格式化。format可以包含与DATE_FORMAT()函数列出的条 <br>目同样的修饰符。&nbsp; <br>mysql&gt; select FROM_UNIXTIME(UNIX_TIMESTAMP(),&nbsp; <br>'%Y %D %M %h:%i:%s %x');&nbsp; <br>-&gt; '1997 23rd December 03:43:30 x'&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">SEC_TO_TIME(seconds)&nbsp; <br>返回seconds参数，变换成小时、分钟和秒，值以'HH:MM:SS'或HHMMSS格式化，取决于函数是在一个字符串还是在数字 <br>上下文中被使用。&nbsp; <br>mysql&gt; select SEC_TO_TIME(2378);&nbsp; <br>-&gt; '00:39:38'&nbsp; <br>mysql&gt; select SEC_TO_TIME(2378) + 0;&nbsp; <br>-&gt; 3938&nbsp; </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">TIME_TO_SEC(time)&nbsp; <br>返回time参数，转换成秒。&nbsp; <br>mysql&gt; select TIME_TO_SEC('22:23:00');&nbsp; <br>-&gt; 80580&nbsp; <br>mysql&gt; select TIME_TO_SEC('00:39:38');&nbsp; <br>-&gt; 2378 </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">&nbsp;</p>
<img src ="http://www.cppblog.com/niewenlong/aggbug/58900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-08-15 00:28 <a href="http://www.cppblog.com/niewenlong/archive/2008/08/15/58900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中Combo Box控件使用大全</title><link>http://www.cppblog.com/niewenlong/archive/2008/08/09/58363.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Fri, 08 Aug 2008 18:48:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2008/08/09/58363.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/58363.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2008/08/09/58363.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/58363.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/58363.html</trackback:ping><description><![CDATA[<p>一、如何添加/删除Combo Box内容<br>1，在Combo Box控件属性的Data标签里面添加，一行表示Combo Box下拉列表中的一行。换行用ctrl+回车。<br>2，在程序初始化时动态添加<br>如：&nbsp;//控件内容初始化<br>&nbsp;CString strTemp;<br>&nbsp;((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;ResetContent();//消除现有所有内容<br>&nbsp;for(int i=1;i&lt;=100;i++)<br>&nbsp;{<br>&nbsp;&nbsp;strTemp.Format("%d",i);<br>&nbsp;&nbsp;((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;AddString(strTemp);<br>&nbsp;}<br>3，下拉的时候添加<br>如：&nbsp;CString strTemp;<br>&nbsp;int iCount=((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;GetCount();//取得目前已经有的行数<br>&nbsp;if(iCount&lt;1)//防止重复多次添加<br>&nbsp;{<br>&nbsp;&nbsp;((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;ResetContent();<br>&nbsp;&nbsp;for(int i=1;i&lt;=100;i++)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;strTemp.Format("%d",i);<br>&nbsp;&nbsp;&nbsp;((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;AddString(strTemp);<br>&nbsp;&nbsp;}<br>&nbsp;}<br>4，删除<br>DeleteString( UINT nIndex )//删除指定行，<br>5，插入<br>InsertString( int nIndex, LPCTSTR lpszItem )//将行插入到指定位置<br>6，查找<br>FindString( int nStartAfter, LPCTSTR lpszItem )//可以在当前所有行中查找指定的字符传的位置，nStartAfter指明从那一行开始进行查找。 <br>int SelectString( int nStartAfter, LPCTSTR lpszItem )//可以选中包含指定字符串的行<br>二、如何控制Combo Box的下拉长度</p>
<p>1，首先要知道两点：一、那就是在设计界面里，点击一下Combo Box的下拉箭头，此时出现的调整框就是Combo Box的下拉调整框。<br>2，二、属性里有个 No integral height 钩选项，表示最大长度为设计长度，如果实际内容比设计长度多，就出现滚动条，少就以实际长度显示。</p>
<p>三、选择其中的某行<br>1，选中：<br>int iPos=((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;GetCurSel();//当前选中的行。<br>2，设置<br>((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;SetCurSel(n)//设置第n行内容为显示的内容。</p>
<p>四、取得Combo Box框内容<br>1取当前内容<br>((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;GetWindowText(strTemp);<br><br>2取其他行内容<br>((CComboBox*)GetDlgItem(IDC_COMBO_CF))-&gt;GetLBText(n,strTemp);</p>
<img src ="http://www.cppblog.com/niewenlong/aggbug/58363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2008-08-09 02:48 <a href="http://www.cppblog.com/niewenlong/archive/2008/08/09/58363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++线程</title><link>http://www.cppblog.com/niewenlong/archive/2007/09/27/33027.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Thu, 27 Sep 2007 08:17:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2007/09/27/33027.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/33027.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2007/09/27/33027.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/33027.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/33027.html</trackback:ping><description><![CDATA[<div class=cnt>
<p><font size=2><strong>使线程同步<br><br></strong>　　在程序中使用多线程时，一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作，而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。<br><br>　　如果不采取适当的措施，其他线程往往会在线程处理任务结束前就去访问处理结果，这就很有可能得到有关处理结果的错误了解。例如，多个线程同时访问同一个全局变量，如果都是读取操作，则不会出现问题。如果一个线程负责改变此变量的值，而其他线程负责同时读取变量内容，则不能保证读取到的数据是经过写线程修改后的。<br><br>　　为了确保读线程读取到的是经过修改的变量，就必须在向变量写入数据时禁止其他线程对其的任何访问，直至赋值过程结束后再解除对其他线程的访问限制。象这种保证线程能了解其他线程任务处理结束后的处理结果而采取的保护措施即为线程同步。<br><br>　　线程同步是一个非常大的话题，包括方方面面的内容。从大的方面讲，线程的同步可分用户模式的线程同步和内核对象的线程同步两大类。用户模式中线程的同步方法主要有原子访问和临界区等方法。其特点是同步速度特别快，适合于对线程运行速度有严格要求的场合。<br><br>　　内核对象的线程同步则主要由事件、等待定时器、信号量以及信号灯等内核对象构成。由于这种同步机制使用了内核对象，使用时必须将线程从用户模式切换到内核模式，而这种转换一般要耗费近千个CPU周期，因此同步速度较慢，但在适用性上却要远优于用户模式的线程同步方式。<br></font></p>
<div><span class=f14><font size=2>　　<strong>临界区</strong><br><br>　　临界区（Critical&nbsp;Section）是一段独占对某些共享资源访问的代码，在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区，那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起，并一直持续到进入临界区的线程离开。临界区在被释放后，其他线程可以继续抢占，并以此达到用原子方式操作共享资源的目的。<br><br>　　临界区在使用时以CRITICAL_SECTION结构对象保护共享资源，并分别用EnterCriticalSection（）和LeaveCriticalSection（）函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection（）的初始化后才能使用，而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用，共享资源依然有被破坏的可能。<br><br><img style="CURSOR: pointer" alt="" src="http://www.yesky.com/image20010518/110093.jpg" align=center vspace=1 border=1><br>图1&nbsp;使用临界区保持线程同步<br><br>　　下面通过一段代码展示了临界区在保护多线程访问的共享资源中的作用。通过两个线程来分别对全局变量g_cArray[10]进行写入操作，用临界区结构对象g_cs来保持线程的同步，并在开启线程前对其进行初始化。为了使实验效果更加明显，体现出临界区的作用，在线程函数对共享资源g_cArray[10]的写入时，以Sleep（）函数延迟1毫秒，使其他线程同其抢占CPU的可能性增大。如果不使用临界区对其进行保护，则共享资源数据将被破坏（参见图1（a）所示计算结果），而使用临界区对线程保持同步后则可以得到正确的结果（参见图1（b）所示计算结果）。代码实现清单附下：<br><br></font>
<p>&nbsp;</p>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;临界区结构对象<br>CRITICAL_SECTION&nbsp;g_cs;<br>//&nbsp;共享资源&nbsp;<br>char&nbsp;g_cArray[10];<br>UINT&nbsp;ThreadProc10(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;进入临界区<br>　EnterCriticalSection(&amp;g_cs);<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[i]&nbsp;=&nbsp;'a';<br>　　Sleep(1);<br>　}<br>　//&nbsp;离开临界区<br>　LeaveCriticalSection(&amp;g_cs);<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc11(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;进入临界区<br>　EnterCriticalSection(&amp;g_cs);<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[10&nbsp;-&nbsp;i&nbsp;-&nbsp;1]&nbsp;=&nbsp;'b';<br>　　Sleep(1);<br>　}<br>　//&nbsp;离开临界区<br>　LeaveCriticalSection(&amp;g_cs);<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnCriticalSection()&nbsp;<br>{<br>　//&nbsp;初始化临界区<br>　InitializeCriticalSection(&amp;g_cs);<br>　//&nbsp;启动线程<br>　AfxBeginThread(ThreadProc10,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc11,&nbsp;NULL);<br>　//&nbsp;等待计算完毕<br>　Sleep(300);<br>　//&nbsp;报告计算结果<br>　CString&nbsp;sResult&nbsp;=&nbsp;CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　在使用临界区时，一般不允许其运行时间过长，只要进入临界区的线程还没有离开，其他所有试图进入此临界区的线程都会被挂起而进入到等待状态，并会在一定程度上影响。程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。如果进入了临界区却一直没有释放，同样也会引起其他线程的长时间等待。换句话说，在执行了EnterCriticalSection（）语句进入临界区后无论发生什么，必须确保与之匹配的LeaveCriticalSection（）都能够被执行到。可以通过添加结构化异常处理代码来确保LeaveCriticalSection（）语句的执行。虽然临界区同步速度很快，但却只能用来同步本进程内的线程，而不可用来同步多个进程中的线程。<br><br>　　MFC为临界区提供有一个<a name=0></a><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">CCriticalSection</strong>类，使用该类进行线程同步处理是非常简单的，只需在线程函数中用<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">CCriticalSection</strong>类成员函数Lock（）和UnLock（）标定出被保护代码片段即可。对于上述代码，可通过<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">CCriticalSection</strong>类将其改写如下：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;MFC临界区类对象<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">CCriticalSection</strong>&nbsp;g_clsCriticalSection;<br>//&nbsp;共享资源&nbsp;<br>char&nbsp;g_cArray[10];<br>UINT&nbsp;ThreadProc20(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;进入临界区<br>　g_clsCriticalSection.Lock();<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[i]&nbsp;=&nbsp;'a';<br>　　Sleep(1);<br>　}<br>　//&nbsp;离开临界区<br>　g_clsCriticalSection.Unlock();<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc21(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;进入临界区<br>　g_clsCriticalSection.Lock();<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[10&nbsp;-&nbsp;i&nbsp;-&nbsp;1]&nbsp;=&nbsp;'b';<br>　　Sleep(1);<br>　}<br>　//&nbsp;离开临界区<br>　g_clsCriticalSection.Unlock();<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnCriticalSectionMfc()&nbsp;<br>{<br>　//&nbsp;启动线程<br>　AfxBeginThread(ThreadProc20,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc21,&nbsp;NULL);<br>　//&nbsp;等待计算完毕<br>　Sleep(300);<br>　//&nbsp;报告计算结果<br>　CString&nbsp;sResult&nbsp;=&nbsp;CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</font></td>
        </tr>
    </tbody>
</table>
</span></div>
<p><span class=f14><font size=2>　　<strong>管理事件内核对象</strong><br><br>　　在前面讲述线程通信时曾使用过事件内核对象来进行线程间的通信，除此之外，事件内核对象也可以通过通知操作的方式来保持线程的同步。对于前面那段使用临界区保持线程同步的代码可用事件对象的线程同步方法改写如下：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;事件句柄<br>HANDLE&nbsp;hEvent&nbsp;=&nbsp;NULL;<br>//&nbsp;共享资源&nbsp;<br>char&nbsp;g_cArray[10];<br>&#8230;&#8230;<br>UINT&nbsp;ThreadProc12(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;等待事件置位<br>　WaitForSingleObject(hEvent,&nbsp;INFINITE);<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[i]&nbsp;=&nbsp;'a';<br>　　Sleep(1);<br>　}<br>　//&nbsp;处理完成后即将事件对象置位<br>　SetEvent(hEvent);<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc13(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;等待事件置位<br>　WaitForSingleObject(hEvent,&nbsp;INFINITE);<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[10&nbsp;-&nbsp;i&nbsp;-&nbsp;1]&nbsp;=&nbsp;'b';<br>　　Sleep(1);<br>　}<br>　//&nbsp;处理完成后即将事件对象置位<br>　SetEvent(hEvent);<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnEvent()&nbsp;<br>{<br>　//&nbsp;创建事件<br>　hEvent&nbsp;=&nbsp;CreateEvent(NULL,&nbsp;FALSE,&nbsp;FALSE,&nbsp;NULL);<br>　//&nbsp;事件置位<br>　SetEvent(hEvent);<br>　//&nbsp;启动线程<br>　AfxBeginThread(ThreadProc12,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc13,&nbsp;NULL);<br>　//&nbsp;等待计算完毕<br>　Sleep(300);<br>　//&nbsp;报告计算结果<br>　CString&nbsp;sResult&nbsp;=&nbsp;CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　在创建线程前，首先创建一个可以自动复位的事件内核对象hEvent，而线程函数则通过WaitForSingleObject（）等待函数无限等待hEvent的置位，只有在事件置位时WaitForSingleObject（）才会返回，被保护的代码将得以执行。对于以自动复位方式创建的事件对象，在其置位后一被WaitForSingleObject（）等待到就会立即复位，也就是说在执行ThreadProc12（）中的受保护代码时，事件对象已经是复位状态的，这时即使有ThreadProc13（）对CPU的抢占，也会由于WaitForSingleObject（）没有hEvent的置位而不能继续执行，也就没有可能破坏受保护的共享资源。在ThreadProc12（）中的处理完成后可以通过SetEvent（）对hEvent的置位而允许ThreadProc13（）对共享资源g_cArray的处理。这里SetEvent（）所起的作用可以看作是对某项特定任务完成的通知。<br><br>　　使用临界区只能同步同一进程中的线程，而使用事件内核对象则可以对进程外的线程进行同步，其前提是得到对此事件对象的访问权。可以通过OpenEvent（）函数获取得到，其函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>HANDLE&nbsp;OpenEvent(<br>　DWORD&nbsp;dwDesiredAccess,&nbsp;//&nbsp;访问标志<br>　BOOL&nbsp;bInheritHandle,&nbsp;//&nbsp;继承标志<br>　LPCTSTR&nbsp;lpName&nbsp;//&nbsp;指向事件对象名的指针<br>);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　如果事件对象已创建（在创建事件时需要指定事件名），函数将返回指定事件的句柄。对于那些在创建事件时没有指定事件名的事件内核对象，可以通过使用内核对象的继承性或是调用DuplicateHandle（）函数来调用CreateEvent（）以获得对指定事件对象的访问权。在获取到访问权后所进行的同步操作与在同一个进程中所进行的线程同步操作是一样的。<br><br>　　如果需要在一个线程中等待多个事件，则用WaitForMultipleObjects（）来等待。WaitForMultipleObjects（）与WaitForSingleObject（）类似，同时监视位于句柄数组中的所有句柄。这些被监视对象的句柄享有平等的优先权，任何一个句柄都不可能比其他句柄具有更高的优先权。WaitForMultipleObjects（）的函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>DWORD&nbsp;WaitForMultipleObjects(<br>　DWORD&nbsp;nCount,&nbsp;//&nbsp;等待句柄数<br>　CONST&nbsp;HANDLE&nbsp;*lpHandles,&nbsp;//&nbsp;句柄数组首地址<br>　BOOL&nbsp;fWaitAll,&nbsp;//&nbsp;等待标志<br>　DWORD&nbsp;dwMilliseconds&nbsp;//&nbsp;等待时间间隔<br>);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　参数nCount指定了要等待的内核对象的数目，存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定，为TRUE时当所有对象都被通知时函数才会返回，为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject（）中的作用是完全一致的。如果等待超时，函数将返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某个值，则说明所有指定对象的状态均为已通知状态（当fWaitAll为TRUE时）或是用以减去WAIT_OBJECT_0而得到发生通知的对象的索引（当fWaitAll为FALSE时）。如果返回值在WAIT_ABANDONED_0与WAIT_ABANDONED_0+nCount-1之间，则表示所有指定对象的状态均为已通知，且其中至少有一个对象是被丢弃的互斥对象（当fWaitAll为TRUE时），或是用以减去WAIT_OBJECT_0表示一个等待正常结束的互斥对象的索引（当fWaitAll为FALSE时）。&nbsp;下面给出的代码主要展示了对WaitForMultipleObjects（）函数的使用。通过对两个事件内核对象的等待来控制线程任务的执行与中途退出：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;存放事件句柄的数组<br>HANDLE&nbsp;hEvents[2];<br>UINT&nbsp;ThreadProc14(LPVOID&nbsp;pParam)<br>{&nbsp;<br>　//&nbsp;等待开启事件<br>　DWORD&nbsp;dwRet1&nbsp;=&nbsp;WaitForMultipleObjects(2,&nbsp;hEvents,&nbsp;FALSE,&nbsp;INFINITE);<br>　//&nbsp;如果开启事件到达则线程开始执行任务<br>　if&nbsp;(dwRet1&nbsp;==&nbsp;WAIT_OBJECT_0)<br>　{<br>　　AfxMessageBox("线程开始工作!");<br>　　while&nbsp;(true)<br>　　{<br>　　　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10000;&nbsp;i++);<br>　　　//&nbsp;在任务处理过程中等待结束事件&nbsp;<br>　　　DWORD&nbsp;dwRet2&nbsp;=&nbsp;WaitForMultipleObjects(2,&nbsp;hEvents,&nbsp;FALSE,&nbsp;0);<br>　　　//&nbsp;如果结束事件置位则立即终止任务的执行<br>　　　if&nbsp;(dwRet2&nbsp;==&nbsp;WAIT_OBJECT_0&nbsp;+&nbsp;1)<br>　　　　break;<br>　　}<br>　}<br>　AfxMessageBox("线程退出!");<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnStartEvent()&nbsp;<br>{<br>　//&nbsp;创建线程<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;2;&nbsp;i++)<br>　　hEvents[i]&nbsp;=&nbsp;CreateEvent(NULL,&nbsp;FALSE,&nbsp;FALSE,&nbsp;NULL);<br>　　//&nbsp;开启线程<br>　　AfxBeginThread(ThreadProc14,&nbsp;NULL);<br>　　//&nbsp;设置事件0(开启事件)<br>　　SetEvent(hEvents[0]);<br>}<br>void&nbsp;CSample08View::OnEndevent()&nbsp;<br>{<br>　//&nbsp;设置事件1(结束事件)<br>　SetEvent(hEvents[1]);<br>}</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　MFC为事件相关处理也提供了一个CEvent类，共包含有除构造函数外的4个成员函数PulseEvent（）、ResetEvent（）、SetEvent（）和UnLock（）。在功能上分别相当与Win32&nbsp;API的PulseEvent（）、ResetEvent（）、SetEvent（）和CloseHandle（）等函数。而构造函数则履行了原CreateEvent（）函数创建事件对象的职责，其函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>CEvent(BOOL&nbsp;bInitiallyOwn&nbsp;=&nbsp;FALSE,&nbsp;BOOL&nbsp;bManualReset&nbsp;=&nbsp;FALSE,&nbsp;LPCTSTR&nbsp;lpszName&nbsp;=&nbsp;NULL,&nbsp;LPSECURITY_ATTRIBUTES&nbsp;lpsaAttribute&nbsp;=&nbsp;NULL&nbsp;);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　按照此缺省设置将创建一个自动复位、初始状态为复位状态的没有名字的事件对象。封装后的CEvent类使用起来更加方便，图2即展示了CEvent类对A、B两线程的同步过程：<br><br><img style="CURSOR: pointer" alt="" src="http://www.yesky.com/image20010518/110094.jpg" align=center vspace=1 border=1><br>图2&nbsp;CEvent类对线程的同步过程示意<br><br>　　B线程在执行到CEvent类成员函数Lock（）时将会发生阻塞，而A线程此时则可以在没有B线程干扰的情况下对共享资源进行处理，并在处理完成后通过成员函数SetEvent（）向B发出事件，使其被释放，得以对A先前已处理完毕的共享资源进行操作。可见，使用CEvent类对线程的同步方法与通过API函数进行线程同步的处理方法是基本一致的。前面的API处理代码可用CEvent类将其改写为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;MFC事件类对象<br>CEvent&nbsp;g_clsEvent;<br>UINT&nbsp;ThreadProc22(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[i]&nbsp;=&nbsp;'a';<br>　　Sleep(1);<br>　}<br>　//&nbsp;事件置位<br>　g_clsEvent.SetEvent();<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc23(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;等待事件<br>　g_clsEvent.Lock();<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[10&nbsp;-&nbsp;i&nbsp;-&nbsp;1]&nbsp;=&nbsp;'b';<br>　　Sleep(1);<br>　}<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnEventMfc()&nbsp;<br>{<br>　//&nbsp;启动线程<br>　AfxBeginThread(ThreadProc22,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc23,&nbsp;NULL);<br>　//&nbsp;等待计算完毕<br>　Sleep(300);<br>　//&nbsp;报告计算结果<br>　CString&nbsp;sResult&nbsp;=&nbsp;CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</font></td>
        </tr>
    </tbody>
</table>
</span><span class=f14><font size=2>　　<strong>信号量内核对象</strong><br><br>　　信号量（Semaphore）内核对象对线程的同步方式与前面几种方法不同，它允许多个线程在同一时刻访问同一资源，但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore（）创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数，每增加一个线程对共享资源的访问，当前可用资源计数就会减1，只要当前可用资源计数是大于0的，就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目，不能在允许其他线程的进入，此时的信号量信号将无法发出。线程在处理完共享资源后，应在离开的同时通过ReleaseSemaphore（）函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。<br><br><img style="CURSOR: pointer" alt="" src="http://www.yesky.com/image20010518/110095.jpg" align=center vspace=1 border=1><br>图3&nbsp;使用信号量对象控制资源<br><br>　　下面结合图例3来演示信号量对象对资源的控制。在图3中，以箭头和白色箭头表示共享资源所允许的最大资源计数和当前可用资源计数。初始如图（a）所示，最大资源计数和当前可用资源计数均为4，此后每增加一个对资源进行访问的线程（用黑色箭头表示）当前资源计数就会相应减1，图（b）即表示的在3个线程对共享资源进行访问时的状态。当进入线程数达到4个时，将如图（c）所示，此时已达到最大资源计数，而当前可用资源计数也已减到0，其他线程无法对共享资源进行访问。在当前占有资源的线程处理完毕而退出后，将会释放出空间，图（d）已有两个线程退出对资源的占有，当前可用计数为2，可以再允许2个线程进入到对资源的处理。可以看出，信号量是通过计数来对线程访问资源进行控制的，而实际上信号量确实也被称作Dijkstra计数器。<br><br>　　使用信号量内核对象进行线程同步主要会用到CreateSemaphore（）、OpenSemaphore（）、ReleaseSemaphore（）、WaitForSingleObject（）和WaitForMultipleObjects（）等函数。其中，CreateSemaphore（）用来创建一个信号量内核对象，其函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>HANDLE&nbsp;CreateSemaphore(<br>　LPSECURITY_ATTRIBUTES&nbsp;lpSemaphoreAttributes,&nbsp;//&nbsp;安全属性指针<br>　LONG&nbsp;lInitialCount,&nbsp;//&nbsp;初始计数<br>　LONG&nbsp;lMaximumCount,&nbsp;//&nbsp;最大计数<br>　LPCTSTR&nbsp;lpName&nbsp;//&nbsp;对象名指针<br>);&nbsp;</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　参数lMaximumCount是一个有符号32位值，定义了允许的最大资源计数，最大取值不能超过4294967295。lpName参数可以为创建的信号量定义一个名字，由于其创建的是一个内核对象，因此在其他进程中可以通过该名字而得到此信号量。OpenSemaphore（）函数即可用来根据信号量名打开在其他进程中创建的信号量，函数原型如下：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>HANDLE&nbsp;OpenSemaphore(<br>　DWORD&nbsp;dwDesiredAccess,&nbsp;//&nbsp;访问标志<br>　BOOL&nbsp;bInheritHandle,&nbsp;//&nbsp;继承标志<br>　LPCTSTR&nbsp;lpName&nbsp;//&nbsp;信号量名<br>);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　在线程离开对共享资源的处理时，必须通过ReleaseSemaphore（）来增加当前可用资源计数。否则将会出现当前正在处理共享资源的实际线程数并没有达到要限制的数值，而其他线程却因为当前可用资源计数为0而仍无法进入的情况。ReleaseSemaphore（）的函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>BOOL&nbsp;ReleaseSemaphore(<br>　HANDLE&nbsp;hSemaphore,&nbsp;//&nbsp;信号量句柄<br>　LONG&nbsp;lReleaseCount,&nbsp;//&nbsp;计数递增数量<br>　LPLONG&nbsp;lpPreviousCount&nbsp;//&nbsp;先前计数<br>);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　该函数将lReleaseCount中的值添加给信号量的当前资源计数，一般将lReleaseCount设置为1，如果需要也可以设置其他的值。WaitForSingleObject（）和WaitForMultipleObjects（）主要用在试图进入共享资源的线程函数入口处，主要用来判断信号量的当前可用资源计数是否允许本线程的进入。只有在当前可用资源计数值大于0时，被监视的信号量内核对象才会得到通知。<br><br>　　信号量的使用特点使其更适用于对Socket（套接字）程序中线程的同步。例如，网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限制，这时可以为没一个用户对服务器的页面请求设置一个线程，而页面则是待保护的共享资源，通过使用信号量对线程的同步作用可以确保在任一时刻无论有多少用户对某一页面进行访问，只有不大于设定的最大用户数目的线程能够进行访问，而其他的访问企图则被挂起，只有在有用户退出对此页面的访问后才有可能进入。下面给出的示例代码即展示了类似的处理过程：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;信号量对象句柄<br>HANDLE&nbsp;hSemaphore;<br>UINT&nbsp;ThreadProc15(LPVOID&nbsp;pParam)<br>{&nbsp;<br>　//&nbsp;试图进入信号量关口<br>　WaitForSingleObject(hSemaphore,&nbsp;INFINITE);<br>　//&nbsp;线程任务处理<br>　AfxMessageBox("线程一正在执行!");<br>　//&nbsp;释放信号量计数<br>　ReleaseSemaphore(hSemaphore,&nbsp;1,&nbsp;NULL);<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc16(LPVOID&nbsp;pParam)<br>{&nbsp;<br>　//&nbsp;试图进入信号量关口<br>　WaitForSingleObject(hSemaphore,&nbsp;INFINITE);<br>　//&nbsp;线程任务处理<br>　AfxMessageBox("线程二正在执行!");<br>　//&nbsp;释放信号量计数<br>　ReleaseSemaphore(hSemaphore,&nbsp;1,&nbsp;NULL);<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc17(LPVOID&nbsp;pParam)<br>{&nbsp;<br>　//&nbsp;试图进入信号量关口<br>　WaitForSingleObject(hSemaphore,&nbsp;INFINITE);<br>　//&nbsp;线程任务处理<br>　AfxMessageBox("线程三正在执行!");<br>　//&nbsp;释放信号量计数<br>　ReleaseSemaphore(hSemaphore,&nbsp;1,&nbsp;NULL);<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnSemaphore()&nbsp;<br>{<br>　//&nbsp;创建信号量对象<br>　hSemaphore&nbsp;=&nbsp;CreateSemaphore(NULL,&nbsp;2,&nbsp;2,&nbsp;NULL);<br>　//&nbsp;开启线程<br>　AfxBeginThread(ThreadProc15,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc16,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc17,&nbsp;NULL);<br>}</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2><img style="CURSOR: pointer" alt="" src="http://www.yesky.com/image20010518/110096.jpg" align=center vspace=1 border=1><br>图4&nbsp;开始进入的两个线程<br><br><img style="CURSOR: pointer" alt="" src="http://www.yesky.com/image20010518/110097.jpg" align=center vspace=1 border=1><br>图5&nbsp;线程二退出后线程三才得以进入<br><br>　　上述代码在开启线程前首先创建了一个初始计数和最大资源计数均为2的信号量对象hSemaphore。即在同一时刻只允许2个线程进入由hSemaphore保护的共享资源。随后开启的三个线程均试图访问此共享资源，在前两个线程试图访问共享资源时，由于hSemaphore的当前可用资源计数分别为2和1，此时的hSemaphore是可以得到通知的，也就是说位于线程入口处的WaitForSingleObject（）将立即返回，而在前两个线程进入到保护区域后，hSemaphore的当前资源计数减少到0，hSemaphore将不再得到通知，WaitForSingleObject（）将线程挂起。直到此前进入到保护区的线程退出后才能得以进入。图4和图5为上述代脉的运行结果。从实验结果可以看出，信号量始终保持了同一时刻不超过2个线程的进入。<br><br>　　在MFC中，通过CSemaphore类对信号量作了表述。该类只具有一个构造函数，可以构造一个信号量对象，并对初始资源计数、最大资源计数、对象名和安全属性等进行初始化，其原型如下：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>CSemaphore(&nbsp;LONG&nbsp;lInitialCount&nbsp;=&nbsp;1,&nbsp;LONG&nbsp;lMaxCount&nbsp;=&nbsp;1,&nbsp;LPCTSTR&nbsp;pstrName&nbsp;=&nbsp;NULL,&nbsp;LPSECURITY_ATTRIBUTES&nbsp;lpsaAttributes&nbsp;=&nbsp;NULL&nbsp;);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　在构造了CSemaphore类对象后，任何一个访问受保护共享资源的线程都必须通过CSemaphore从父类CSyncObject类继承得到的Lock（）和UnLock（）成员函数来访问或释放CSemaphore对象。与前面介绍的几种通过MFC类保持线程同步的方法类似，通过CSemaphore类也可以将前面的线程同步代码进行改写，这两种使用信号量的线程同步方法无论是在实现原理上还是从实现结果上都是完全一致的。下面给出经MFC改写后的信号量线程同步代码：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;MFC信号量类对象<br>CSemaphore&nbsp;g_clsSemaphore(2,&nbsp;2);<br>UINT&nbsp;ThreadProc24(LPVOID&nbsp;pParam)<br>{&nbsp;<br>　//&nbsp;试图进入信号量关口<br>　g_clsSemaphore.Lock();<br>　//&nbsp;线程任务处理<br>　AfxMessageBox("线程一正在执行!");<br>　//&nbsp;释放信号量计数<br>　g_clsSemaphore.Unlock();<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc25(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;试图进入信号量关口<br>　g_clsSemaphore.Lock();<br>　//&nbsp;线程任务处理<br>　AfxMessageBox("线程二正在执行!");<br>　//&nbsp;释放信号量计数<br>　g_clsSemaphore.Unlock();<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc26(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;试图进入信号量关口<br>　g_clsSemaphore.Lock();<br>　//&nbsp;线程任务处理<br>　AfxMessageBox("线程三正在执行!");<br>　//&nbsp;释放信号量计数<br>　g_clsSemaphore.Unlock();<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnSemaphoreMfc()&nbsp;<br>{<br>　//&nbsp;开启线程<br>　AfxBeginThread(ThreadProc24,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc25,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc26,&nbsp;NULL);<br>}</font></td>
        </tr>
    </tbody>
</table>
</span><span class=f14><font size=2>　　<strong>互斥内核对象</strong><br><br>　　互斥（Mutex）是一种用途非常广泛的内核对象。能够保证多个线程对同一共享资源的互斥访问。同临界区有些类似，只有拥有互斥对象的线程才具有访问资源的权限，由于互斥对象只有一个，因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出，以便其他线程在获得后得以访问资源。与其他几种内核对象不同，互斥对象在操作系统中拥有特殊代码，并由操作系统来管理，操作系统甚至还允许其进行一些其他内核对象所不能进行的非常规操作。为便于理解，可参照图6给出的互斥内核对象的工作模型：<br><br><img style="CURSOR: pointer" alt="" src="http://www.yesky.com/image20010518/110098.jpg" align=center vspace=1 border=1><br>图6&nbsp;使用互斥内核对象对共享资源的保护<br><br>　　图（a）中的箭头为要访问资源（矩形框）的线程，但只有第二个线程拥有互斥对象（黑点）并得以进入到共享资源，而其他线程则会被排斥在外（如图（b）所示）。当此线程处理完共享资源并准备离开此区域时将把其所拥有的互斥对象交出（如图（c）所示），其他任何一个试图访问此资源的线程都有机会得到此互斥对象。<br><br>　　以互斥内核对象来保持线程同步可能用到的函数主要有CreateMutex（）、OpenMutex（）、ReleaseMutex（）、WaitForSingleObject（）和WaitForMultipleObjects（）等。在使用互斥对象前，首先要通过CreateMutex（）或OpenMutex（）创建或打开一个互斥对象。CreateMutex（）函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>HANDLE&nbsp;CreateMutex(<br>　LPSECURITY_ATTRIBUTES&nbsp;lpMutexAttributes,&nbsp;//&nbsp;安全属性指针<br>　BOOL&nbsp;bInitialOwner,&nbsp;//&nbsp;初始拥有者<br>　LPCTSTR&nbsp;lpName&nbsp;//&nbsp;互斥对象名<br>);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　参数bInitialOwner主要用来控制互斥对象的初始状态。一般多将其设置为FALSE，以表明互斥对象在创建时并没有为任何线程所占有。如果在创建互斥对象时指定了对象名，那么可以在本进程其他地方或是在其他进程通过OpenMutex（）函数得到此互斥对象的句柄。OpenMutex（）函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>HANDLE&nbsp;OpenMutex(<br>　DWORD&nbsp;dwDesiredAccess,&nbsp;//&nbsp;访问标志<br>　BOOL&nbsp;bInheritHandle,&nbsp;//&nbsp;继承标志<br>　LPCTSTR&nbsp;lpName&nbsp;//&nbsp;互斥对象名<br>);&nbsp;</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　当目前对资源具有访问权的线程不再需要访问此资源而要离开时，必须通过ReleaseMutex（）函数来释放其拥有的互斥对象，其函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>BOOL&nbsp;ReleaseMutex(HANDLE&nbsp;hMutex);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　其唯一的参数hMutex为待释放的互斥对象句柄。至于WaitForSingleObject（）和WaitForMultipleObjects（）等待函数在互斥对象保持线程同步中所起的作用与在其他内核对象中的作用是基本一致的，也是等待互斥内核对象的通知。但是这里需要特别指出的是：在互斥对象通知引起调用等待函数返回时，等待函数的返回值不再是通常的WAIT_OBJECT_0（对于WaitForSingleObject（）函数）或是在WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1之间的一个值（对于WaitForMultipleObjects（）函数），而是将返回一个WAIT_ABANDONED_0（对于WaitForSingleObject（）函数）或是在WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1之间的一个值（对于WaitForMultipleObjects（）函数）。以此来表明线程正在等待的互斥对象由另外一个线程所拥有，而此线程却在使用完共享资源前就已经终止。除此之外，使用互斥对象的方法在等待线程的可调度性上同使用其他几种内核对象的方法也有所不同，其他内核对象在没有得到通知时，受调用等待函数的作用，线程将会挂起，同时失去可调度性，而使用互斥的方法却可以在等待的同时仍具有可调度性，这也正是互斥对象所能完成的非常规操作之一。<br><br>　　在编写程序时，互斥对象多用在对那些为多个线程所访问的内存块的保护上，可以确保任何线程在处理此内存块时都对其拥有可靠的独占访问权。下面给出的示例代码即通过互斥内核对象hMutex对共享内存快g_cArray[]进行线程的独占访问保护。下面给出实现代码清单：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;互斥对象<br>HANDLE&nbsp;hMutex&nbsp;=&nbsp;NULL;<br>char&nbsp;g_cArray[10];<br>UINT&nbsp;ThreadProc18(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;等待互斥对象通知<br>　WaitForSingleObject(hMutex,&nbsp;INFINITE);<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[i]&nbsp;=&nbsp;'a';<br>　　Sleep(1);<br>　}<br>　//&nbsp;释放互斥对象<br>　ReleaseMutex(hMutex);<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc19(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;等待互斥对象通知<br>　WaitForSingleObject(hMutex,&nbsp;INFINITE);<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[10&nbsp;-&nbsp;i&nbsp;-&nbsp;1]&nbsp;=&nbsp;'b';<br>　　Sleep(1);<br>　}<br>　//&nbsp;释放互斥对象<br>　ReleaseMutex(hMutex);<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnMutex()&nbsp;<br>{<br>　//&nbsp;创建互斥对象<br>　hMutex&nbsp;=&nbsp;CreateMutex(NULL,&nbsp;FALSE,&nbsp;NULL);<br>　//&nbsp;启动线程<br>　AfxBeginThread(ThreadProc18,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc19,&nbsp;NULL);<br>　//&nbsp;等待计算完毕<br>　Sleep(300);<br>　//&nbsp;报告计算结果<br>　CString&nbsp;sResult&nbsp;=&nbsp;CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}&nbsp;</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　互斥对象在MFC中通过CMutex类进行表述。使用CMutex类的方法非常简单，在构造CMutex类对象的同时可以指明待查询的互斥对象的名字，在构造函数返回后即可访问此互斥变量。CMutex类也是只含有构造函数这唯一的成员函数，当完成对互斥对象保护资源的访问后，可通过调用从父类CSyncObject继承的UnLock（）函数完成对互斥对象的释放。CMutex类构造函数原型为：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>CMutex(&nbsp;BOOL&nbsp;bInitiallyOwn&nbsp;=&nbsp;FALSE,&nbsp;LPCTSTR&nbsp;lpszName&nbsp;=&nbsp;NULL,&nbsp;LPSECURITY_ATTRIBUTES&nbsp;lpsaAttribute&nbsp;=&nbsp;NULL&nbsp;);</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　该类的适用范围和实现原理与API方式创建的互斥内核对象是完全类似的，但要简洁的多，下面给出就是对前面的示例代码经CMutex类改写后的程序实现清单：<br><br></font>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td><font size=2>//&nbsp;MFC互斥类对象<br>CMutex&nbsp;g_clsMutex(FALSE,&nbsp;NULL);<br>UINT&nbsp;ThreadProc27(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;等待互斥对象通知<br>　g_clsMutex.Lock();<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[i]&nbsp;=&nbsp;'a';<br>　　Sleep(1);<br>　}<br>　//&nbsp;释放互斥对象<br>　g_clsMutex.Unlock();<br>　return&nbsp;0;<br>}<br>UINT&nbsp;ThreadProc28(LPVOID&nbsp;pParam)<br>{<br>　//&nbsp;等待互斥对象通知<br>　g_clsMutex.Lock();<br>　//&nbsp;对共享资源进行写入操作<br>　for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;10;&nbsp;i++)<br>　{<br>　　g_cArray[10&nbsp;-&nbsp;i&nbsp;-&nbsp;1]&nbsp;=&nbsp;'b';<br>　　Sleep(1);<br>　}<br>　//&nbsp;释放互斥对象<br>　g_clsMutex.Unlock();<br>　return&nbsp;0;<br>}<br>&#8230;&#8230;<br>void&nbsp;CSample08View::OnMutexMfc()&nbsp;<br>{<br>　//&nbsp;启动线程<br>　AfxBeginThread(ThreadProc27,&nbsp;NULL);<br>　AfxBeginThread(ThreadProc28,&nbsp;NULL);<br>　//&nbsp;等待计算完毕<br>　Sleep(300);<br>　//&nbsp;报告计算结果<br>　CString&nbsp;sResult&nbsp;=&nbsp;CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</font></td>
        </tr>
    </tbody>
</table>
<br><font size=2>　　<strong>小结</strong><br><br>　　线程的使用使程序处理更够更加灵活，而这种灵活同样也会带来各种不确定性的可能。尤其是在多个线程对同一公共变量进行访问时。虽然未使用线程同步的程序代码在逻辑上或许没有什么问题，但为了确保程序的正确、可靠运行，必须在适当的场合采取线程同步措施。</font></span></p>
</div>
<img src ="http://www.cppblog.com/niewenlong/aggbug/33027.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2007-09-27 16:17 <a href="http://www.cppblog.com/niewenlong/archive/2007/09/27/33027.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何让你的程序安全通过windows防火墙 </title><link>http://www.cppblog.com/niewenlong/archive/2007/09/24/32786.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 24 Sep 2007 06:57:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2007/09/24/32786.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/32786.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2007/09/24/32786.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/32786.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/32786.html</trackback:ping><description><![CDATA[<p><font face=Arial size=1>大家开发网络程序,经常要连接其他主机,如果在xp上运行,一定会提示你,只有选择解除阻止才能实现正常的网络连接.那么有没有办法在防火墙的例外列表里面通过编程的方式加入自己的程序呢?<br>&nbsp;当然有了,不然就不要介绍了<img height=19 src="http://www.cppblog.com/Emoticons/teeth_smile.gif" width=19 border=0><br>xp的系统目录下面有个hnetcfg.dll就是这个编程接口,头文件是netfw.h,初始化代码如下:<br>INetFwProfile* m_pFireWallProfile=NULL;<br></font></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">HRESULT&nbsp;hr&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;S_FALSE;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;INetFwMgr</span> <span style="COLOR: #000000">*</span> <span style="COLOR: #000000">&nbsp;fwMgr&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;NULL;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;INetFwPolicy</span> <span style="COLOR: #000000">*</span> <span style="COLOR: #000000">&nbsp;fwPolicy&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;NULL;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;FW_ERROR_CODE&nbsp;ret&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;FW_NOERROR;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">try</span> <span style="COLOR: #000000"><br><img id=Codehighlighter1_120_710_Open_Image onclick="this.style.display='none'; Codehighlighter1_120_710_Open_Text.style.display='none'; Codehighlighter1_120_710_Closed_Image.style.display='inline'; Codehighlighter1_120_710_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_120_710_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_120_710_Closed_Text.style.display='none'; Codehighlighter1_120_710_Open_Image.style.display='inline'; Codehighlighter1_120_710_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span id=Codehighlighter1_120_710_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"> </span><span id=Codehighlighter1_120_710_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(&nbsp;m_pFireWallProfile&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">throw</span> <span style="COLOR: #000000">&nbsp;FW_ERR_INITIALIZED;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;Create&nbsp;an&nbsp;instance&nbsp;of&nbsp;the&nbsp;firewall&nbsp;settings&nbsp;manager.</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;CoCreateInstance(&nbsp;__uuidof(NetFwMgr),&nbsp;NULL,&nbsp;CLSCTX_INPROC_SERVER,&nbsp;__uuidof(&nbsp;INetFwMgr),&nbsp;(</span> <span style="COLOR: #0000ff">void</span> <span style="COLOR: #000000">**</span> <span style="COLOR: #000000">)</span> <span style="COLOR: #000000">&amp;</span> <span style="COLOR: #000000">fwMgr&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(&nbsp;FAILED(&nbsp;hr&nbsp;))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">throw</span> <span style="COLOR: #000000">&nbsp;FW_ERR_CREATE_SETTING_MANAGER;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;Retrieve&nbsp;the&nbsp;local&nbsp;firewall&nbsp;policy.</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;fwMgr</span> <span style="COLOR: #000000">-&gt;</span> <span style="COLOR: #000000">get_LocalPolicy(&nbsp;</span> <span style="COLOR: #000000">&amp;</span> <span style="COLOR: #000000">fwPolicy&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(&nbsp;FAILED(&nbsp;hr&nbsp;))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">throw</span> <span style="COLOR: #000000">&nbsp;FW_ERR_LOCAL_POLICY;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">//</span> <span style="COLOR: #008000">&nbsp;Retrieve&nbsp;the&nbsp;firewall&nbsp;profile&nbsp;currently&nbsp;in&nbsp;effect</span> <span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;fwPolicy</span> <span style="COLOR: #000000">-&gt;</span> <span style="COLOR: #000000">get_CurrentProfile(&nbsp;</span> <span style="COLOR: #000000">&amp;</span> <span style="COLOR: #000000">m_pFireWallProfile&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(&nbsp;FAILED(&nbsp;hr&nbsp;))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">throw</span> <span style="COLOR: #000000">&nbsp;FW_ERR_PROFILE;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">catch</span> <span style="COLOR: #000000">(&nbsp;FW_ERROR_CODE&nbsp;nError)<br><img id=Codehighlighter1_743_762_Open_Image onclick="this.style.display='none'; Codehighlighter1_743_762_Open_Text.style.display='none'; Codehighlighter1_743_762_Closed_Image.style.display='inline'; Codehighlighter1_743_762_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_743_762_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_743_762_Closed_Text.style.display='none'; Codehighlighter1_743_762_Open_Image.style.display='inline'; Codehighlighter1_743_762_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span id=Codehighlighter1_743_762_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"> </span><span id=Codehighlighter1_743_762_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;nError;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top> <br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(&nbsp;fwPolicy&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fwPolicy</span> <span style="COLOR: #000000">-&gt;</span> <span style="COLOR: #000000">Release();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(&nbsp;fwMgr&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fwMgr</span> <span style="COLOR: #000000">-&gt;</span> <span style="COLOR: #000000">Release();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;ret;</span> </div>
将程序名称加入例外列表:<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">WinXPSP2FireWall::AddApplication(&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;wchar_t</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;lpszProcessImageFileName,&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;wchar_t</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;lpszRegisterName&nbsp;)<br><img id=Codehighlighter1_109_2313_Open_Image onclick="this.style.display='none'; Codehighlighter1_109_2313_Open_Text.style.display='none'; Codehighlighter1_109_2313_Closed_Image.style.display='inline'; Codehighlighter1_109_2313_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_109_2313_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_109_2313_Closed_Text.style.display='none'; Codehighlighter1_109_2313_Open_Image.style.display='inline'; Codehighlighter1_109_2313_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_109_2313_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_109_2313_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;FW_ERROR_CODE&nbsp;ret&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;FW_NOERROR;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HRESULT&nbsp;hr;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bAppEnable;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;BSTR&nbsp;bstrProcessImageFileName&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;BSTR&nbsp;bstrRegisterName&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;INetFwAuthorizedApplication</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pFWApp&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;INetFwAuthorizedApplications</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;pFWApps&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;NULL;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_344_2090_Open_Image onclick="this.style.display='none'; Codehighlighter1_344_2090_Open_Text.style.display='none'; Codehighlighter1_344_2090_Closed_Image.style.display='inline'; Codehighlighter1_344_2090_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_344_2090_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_344_2090_Closed_Text.style.display='none'; Codehighlighter1_344_2090_Open_Image.style.display='inline'; Codehighlighter1_344_2090_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_344_2090_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_344_2090_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;m_pFireWallProfile&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;NULL&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_INITIALIZED;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;lpszProcessImageFileName&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;NULL&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000">&nbsp;lpszRegisterName&nbsp;&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;NULL&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_INVALID_ARG;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;First&nbsp;of&nbsp;all,&nbsp;check&nbsp;the&nbsp;application&nbsp;is&nbsp;already&nbsp;authorized;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FW_ERROR_CODE&nbsp;&nbsp;nError&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">IsAppEnabled(&nbsp;lpszProcessImageFileName,&nbsp;bAppEnable&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;nError&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;FW_NOERROR&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;nError;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Only&nbsp;add&nbsp;the&nbsp;application&nbsp;if&nbsp;it&nbsp;isn't&nbsp;authorized</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;bAppEnable&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;FALSE&nbsp;)<br><img id=Codehighlighter1_790_2087_Open_Image onclick="this.style.display='none'; Codehighlighter1_790_2087_Open_Text.style.display='none'; Codehighlighter1_790_2087_Closed_Image.style.display='inline'; Codehighlighter1_790_2087_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_790_2087_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_790_2087_Closed_Text.style.display='none'; Codehighlighter1_790_2087_Open_Image.style.display='inline'; Codehighlighter1_790_2087_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_790_2087_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_790_2087_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Retrieve&nbsp;the&nbsp;authorized&nbsp;application&nbsp;collection</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;m_pFireWallProfile</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">get_AuthorizedApplications(&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pFWApps&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;FAILED(&nbsp;hr&nbsp;))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_AUTH_APPLICATIONS;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Create&nbsp;an&nbsp;instance&nbsp;of&nbsp;an&nbsp;authorized&nbsp;application</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CoCreateInstance(&nbsp;__uuidof(NetFwAuthorizedApplication),&nbsp;NULL,&nbsp;CLSCTX_INPROC_SERVER,&nbsp;__uuidof(INetFwAuthorizedApplication),&nbsp;(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pFWApp);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;FAILED(&nbsp;hr&nbsp;))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_CREATE_APP_INSTANCE;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Allocate&nbsp;a&nbsp;BSTR&nbsp;for&nbsp;the&nbsp;Process&nbsp;Image&nbsp;FileName</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bstrProcessImageFileName&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;SysAllocString(&nbsp;lpszProcessImageFileName&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;SysStringLen(&nbsp;bstrProcessImageFileName&nbsp;)&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_SYS_ALLOC_STRING;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Set&nbsp;the&nbsp;process&nbsp;image&nbsp;file&nbsp;name</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;pFWApp</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">put_ProcessImageFileName(&nbsp;bstrProcessImageFileName&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;FAILED(&nbsp;hr&nbsp;)&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_PUT_PROCESS_IMAGE_NAME;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Allocate&nbsp;a&nbsp;BSTR&nbsp;for&nbsp;register&nbsp;name</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bstrRegisterName&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;SysAllocString(&nbsp;lpszRegisterName&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;SysStringLen(&nbsp;bstrRegisterName&nbsp;)&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_SYS_ALLOC_STRING;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Set&nbsp;a&nbsp;registered&nbsp;name&nbsp;of&nbsp;the&nbsp;process</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;pFWApp</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">put_Name(&nbsp;bstrRegisterName&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;FAILED(&nbsp;hr&nbsp;))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_PUT_REGISTER_NAME;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Add&nbsp;the&nbsp;application&nbsp;to&nbsp;the&nbsp;collection</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;pFWApps</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Add(&nbsp;pFWApp&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;FAILED(&nbsp;hr&nbsp;))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000">&nbsp;FW_ERR_ADD_TO_COLLECTION;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(&nbsp;FW_ERROR_CODE&nbsp;nError&nbsp;)<br><img id=Codehighlighter1_2124_2143_Open_Image onclick="this.style.display='none'; Codehighlighter1_2124_2143_Open_Text.style.display='none'; Codehighlighter1_2124_2143_Closed_Image.style.display='inline'; Codehighlighter1_2124_2143_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_2124_2143_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2124_2143_Closed_Text.style.display='none'; Codehighlighter1_2124_2143_Open_Image.style.display='inline'; Codehighlighter1_2124_2143_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_2124_2143_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2124_2143_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;nError;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;SysFreeString(&nbsp;bstrProcessImageFileName&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;SysFreeString(&nbsp;bstrRegisterName&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;pFWApp&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pFWApp</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Release();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;pFWApps&nbsp;)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pFWApps</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Release();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;ret;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p class=postfoot>&nbsp;</p>
<img src ="http://www.cppblog.com/niewenlong/aggbug/32786.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2007-09-24 14:57 <a href="http://www.cppblog.com/niewenlong/archive/2007/09/24/32786.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Socket API 使用小结 </title><link>http://www.cppblog.com/niewenlong/archive/2007/09/24/32785.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 24 Sep 2007 06:54:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2007/09/24/32785.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/32785.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2007/09/24/32785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/32785.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/32785.html</trackback:ping><description><![CDATA[一、WSAStartup函数<br>&nbsp;&nbsp;&nbsp;int&nbsp;WSAStartup(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WORD&nbsp;wVersionRequested,&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPWSADATA&nbsp;lpWSAData&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;使用Socket的程序在使用Socket之前必须调用WSAStartup函数。该函数的第一个参数指明程序请求使用的Socket版本，其中高位字节指明副版本、低位字节指明主版本；操作系统利用第二个参数返回请求的Socket的版本信息。当一个应用程序调用WSAStartup函数时，操作系统根据请求的Socket版本来搜索相应的Socket库，然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。该函数执行成功后返回0。<br>例：假如一个程序要使用2.1版本的Socket,那么程序代码如下<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wVersionRequested&nbsp;=&nbsp;MAKEWORD(&nbsp;2,&nbsp;1&nbsp;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;err&nbsp;=&nbsp;WSAStartup(&nbsp;wVersionRequested,&nbsp;&amp;wsaData&nbsp;);<br><br>二、WSACleanup函数<br>&nbsp;&nbsp;&nbsp;int&nbsp;WSACleanup&nbsp;(void);<br>&nbsp;&nbsp;&nbsp;应用程序在完成对请求的Socket库的使用后，要调用WSACleanup函数来解除与Socket库的绑定并且释放Socket库所占用的系统资源。<br><br>三、socket函数<br>&nbsp;&nbsp;SOCKET&nbsp;socket(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;af,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;type,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;protocol&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;应用程序调用socket函数来创建一个能够进行网络通信的套接字。第一个参数指定应用程序使用的通信协议的协议族，对于TCP/IP协议族，该参数置PF_INET;第二个参数指定要创建的套接字类型，流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM；第三个参数指定应用程序所使用的通信协议。该函数如果调用成功就返回新创建的套接字的描述符，如果失败就返回INVALID_SOCKET。套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表，该表中存放着套接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符，另一个字段存放套接字数据结构的地址，因此根据套接字描述符就可以找到其对应的套接字数据结构。每个进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。下面是一个创建流套接字的例子：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;protoent&nbsp;*ppe;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ppe=getprotobyname("tcp");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;ListenSocket=socket(PF_INET,SOCK_STREAM,ppe-&gt;p_proto);<br><br>四、closesocket函数<br>&nbsp;&nbsp;int&nbsp;closesocket(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;s&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;closesocket函数用来关闭一个描述符为s套接字。由于每个进程中都有一个套接字描述符表，表中的每个套接字描述符都对应了一个位于操作系统缓冲区中的套接字数据结构，因此有可能有几个套接字描述符指向同一个套接字数据结构。套接字数据结构中专门有一个字段存放该结构的被引用次数，即有多少个套接字描述符指向该结构。当调用closesocket函数时，操作系统先检查套接字数据结构中的该字段的值，如果为1，就表明只有一个套接字描述符指向它，因此操作系统就先把s在套接字描述符表中对应的那条表项清除，并且释放s对应的套接字数据结构；如果该字段大于1，那么操作系统仅仅清除s在套接字描述符表中的对应表项，并且把s对应的套接字数据结构的引用次数减1。<br>closesocket函数如果执行成功就返回0，否则返回SOCKET_ERROR。<br><br>五、send函数<br>&nbsp;&nbsp;int&nbsp;send(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;s,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char&nbsp;FAR&nbsp;*buf,&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;len,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;flags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求，而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符；第二个参数指明一个存放应用程序要发送数据的缓冲区；第三个参数指明实际要发送的数据的字节数；第四个参数一般置0。这里只描述同步Socket的send函数的执行流程。当调用该函数时，send先比较待发送数据的长度len和套接字s的发送缓冲区的长度，如果len大于s的发送缓冲区的长度，该函数返回SOCKET_ERROR；如果len小于或者等于s的发送缓冲区的长度，那么send先检查协议是否正在发送s的发送缓冲中的数据，如果是就等待协议把数据发送完，如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据，那么send就比较s的发送缓冲区的剩余空间和len，如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完，如果len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里（注意并不是send把s的发送缓冲中的数据传到连接的另一端的，而是协议传的，send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里）。如果send函数copy数据成功，就返回实际copy的字节数，如果send在copy数据时出现错误，那么send就返回SOCKET_ERROR；如果send在等待协议传送数据时网络断开的话，那么send函数也返回SOCKET_ERROR。要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了，但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话，那么下一个Socket函数就会返回SOCKET_ERROR。（每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续，如果在等待时出现网络错误，那么该Socket函数就返回SOCKET_ERROR）<br>注意：在Unix系统下，如果send在等待协议传送数据时网络断开的话，调用send的进程会接收到一个SIGPIPE信号，进程对该信号的默认处理是进程终止。<br><br>六、recv函数<br>&nbsp;&nbsp;&nbsp;int&nbsp;recv(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;s,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;FAR&nbsp;*buf,&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;len,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;flags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符；第二个参数指明一个缓冲区，该缓冲区用来存放recv函数接收到的数据；第三个参数指明buf的长度；第四个参数一般置0。这里只描述同步Socket的recv函数的执行流程。当应用程序调用recv函数时，recv先等待s的发送缓冲中的数据被协议传送完毕，如果协议在传送s的发送缓冲中的数据时出现网络错误，那么recv函数返回SOCKET_ERROR，如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后，recv先检查套接字s的接收缓冲区，如果s接收缓冲区中没有数据或者协议正在接收数据，那么recv就一直等待，只到协议把数据接收完毕。当协议把数据接收完毕，recv函数就把s的接收缓冲中的数据copy到buf中（注意协议接收到的数据可能大于buf的长度，所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据，真正的接收数据是协议来完成的），recv函数返回其实际copy的字节数。如果recv在copy时出错，那么它返回SOCKET_ERROR；如果recv函数在等待协议接收数据时网络中断了，那么它返回0。<br>注意：在Unix系统下，如果recv函数在等待协议接收数据时网络断开了，那么调用recv的进程会接收到一个SIGPIPE信号，进程对该信号的默认处理是进程终止。<br><br>七、bind函数<br>&nbsp;&nbsp;int&nbsp;bind(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;s,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;struct&nbsp;sockaddr&nbsp;FAR&nbsp;*name,&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;namelen&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;当创建了一个Socket以后，套接字数据结构中有一个默认的IP地址和默认的端口号。一个服务程序必须调用bind函数来给其绑定一个IP地址和一个特定的端口号。客户程序一般不必调用bind函数来为其Socket绑定IP地址和断口号。该函数的第一个参数指定待绑定的Socket描述符；第二个参数指定一个sockaddr结构，该结构是这样定义的：&nbsp;<br>struct&nbsp;sockaddr&nbsp;{&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u_short&nbsp;sa_family;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;sa_data[14];&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;sa_family指定地址族，对于TCP/IP协议族的套接字，给其置AF_INET。当对TCP/IP协议族的套接字进行绑定时，我们通常使用另一个地址结构：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr_in&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;short&nbsp;&nbsp;&nbsp;sin_family;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u_short&nbsp;sin_port;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;&nbsp;in_addr&nbsp;sin_addr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;sin_zero[8];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;其中sin_family置AF_INET；sin_port指明端口号；sin_addr结构体中只有一个唯一的字段s_addr，表示IP地址，该字段是一个整数，一般用函数inet_addr（）把字符串形式的IP地址转换成unsigned&nbsp;long型的整数值后再置给s_addr。有的服务器是多宿主机，至少有两个网卡，那么运行在这样的服务器上的服务程序在为其Socket绑定IP地址时可以把htonl(INADDR_ANY)置给s_addr，这样做的好处是不论哪个网段上的客户程序都能与该服务程序通信；如果只给运行在多宿主机上的服务程序的Socket绑定一个固定的IP地址，那么就只有与该IP地址处于同一个网段上的客户程序才能与该服务程序通信。我们用0来填充sin_zero数组，目的是让sockaddr_in结构的大小与sockaddr结构的大小一致。下面是一个bind函数调用的例子：<br>&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr_in&nbsp;saddr；<br>&nbsp;&nbsp;&nbsp;saddr.sin_family&nbsp;=&nbsp;AF_INET;<br>&nbsp;&nbsp;&nbsp;saddr.sin_port&nbsp;=&nbsp;htons(8888);<br>&nbsp;&nbsp;&nbsp;saddr.sin_addr.s_addr&nbsp;=&nbsp;htonl(INADDR_ANY);<br>&nbsp;&nbsp;&nbsp;bind(ListenSocket,(struct&nbsp;sockaddr&nbsp;*)&amp;saddr,sizeof(saddr))；<br><br>八、listen函数<br>&nbsp;&nbsp;&nbsp;int&nbsp;listen(&nbsp;SOCKET&nbsp;s,&nbsp;int&nbsp;backlog&nbsp;);<br>&nbsp;&nbsp;&nbsp;服务程序可以调用listen函数使其流套接字s处于监听状态。处于监听状态的流套接字s将维护一个客户连接请求队列，该队列最多容纳backlog个客户连接请求。假如该函数执行成功，则返回0；如果执行失败，则返回SOCKET_ERROR。<br><br>九、accept函数<br>&nbsp;&nbsp;&nbsp;SOCKET&nbsp;accept(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;s,&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr&nbsp;FAR&nbsp;*addr,&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;FAR&nbsp;*addrlen&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求，并且创建一个新的套接字来与客户套接字创建连接通道，如果连接成功，就返回新创建的套接字的描述符，以后与客户套接字交换数据的是新创建的套接字；如果失败就返回INVALID_SOCKET。该函数的第一个参数指定处于监听状态的流套接字；操作系统利用第二个参数来返回新创建的套接字的地址结构；操作系统利用第三个参数来返回新创建的套接字的地址结构的长度。下面是一个调用accept的例子：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr_in&nbsp;ServerSocketAddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;addrlen;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addrlen=sizeof(ServerSocketAddr);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServerSocket=accept(ListenSocket,(struct&nbsp;sockaddr&nbsp;*)&amp;ServerSocketAddr,&amp;addrlen);<br><br>十、connect函数<br>&nbsp;&nbsp;&nbsp;int&nbsp;connect(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SOCKET&nbsp;s,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;struct&nbsp;sockaddr&nbsp;FAR&nbsp;*name,&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;namelen&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;);<br>&nbsp;&nbsp;&nbsp;客户程序调用connect函数来使客户Socket&nbsp;s与监听于name所指定的计算机的特定端口上的服务Socket进行连接。如果连接成功，connect返回0；如果失败则返回SOCKET_ERROR。下面是一个例子：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;sockaddr_in&nbsp;daddr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset((void&nbsp;*)&amp;daddr,0,sizeof(daddr));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;daddr.sin_family=AF_INET;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;daddr.sin_port=htons(8888);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;daddr.sin_addr.s_addr=inet_addr("133.197.22.4");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connect(ClientSocket,(struct&nbsp;sockaddr&nbsp;*)&amp;daddr,sizeof(daddr));&nbsp;<br>
<img src ="http://www.cppblog.com/niewenlong/aggbug/32785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2007-09-24 14:54 <a href="http://www.cppblog.com/niewenlong/archive/2007/09/24/32785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++线程同步技术 </title><link>http://www.cppblog.com/niewenlong/archive/2007/09/24/32784.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 24 Sep 2007 06:53:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2007/09/24/32784.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/32784.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2007/09/24/32784.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/32784.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/32784.html</trackback:ping><description><![CDATA[<div class=postText>
<p>线程同步的方式有：<br>　　临界区<br>　　管理事件内核对象<br>　　信号量内核对象<br>　　互斥内核对象<br>分别介绍如下：<br><br><strong>使线程同步<br><br></strong>　　在程序中使用多线程时，一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作，而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。<br><br>　　如果不采取适当的措施，其他线程往往会在线程处理任务结束前就去访问处理结果，这就很有可能得到有关处理结果的错误了解。例如，多个线程同时访问同一个全局变量，如果都是读取操作，则不会出现问题。如果一个线程负责改变此变量的值，而其他线程负责同时读取变量内容，则不能保证读取到的数据是经过写线程修改后的。<br><br>　　为了确保读线程读取到的是经过修改的变量，就必须在向变量写入数据时禁止其他线程对其的任何访问，直至赋值过程结束后再解除对其他线程的访问限制。象这种保证线程能了解其他线程任务处理结束后的处理结果而采取的保护措施即为线程同步。<br><br>　　线程同步是一个非常大的话题，包括方方面面的内容。从大的方面讲，线程的同步可分用户模式的线程同步和内核对象的线程同步两大类。用户模式中线程的同步方法主要有原子访问和临界区等方法。其特点是同步速度特别快，适合于对线程运行速度有严格要求的场合。<br><br>　　内核对象的线程同步则主要由事件、等待定时器、信号量以及信号灯等内核对象构成。由于这种同步机制使用了内核对象，使用时必须将线程从用户模式切换到内核模式，而这种转换一般要耗费近千个CPU周期，因此同步速度较慢，但在适用性上却要远优于用户模式的线程同步方式。<br><br><strong>临界区<br><br></strong>　　临界区（Critical Section）是一段独占对某些共享资源访问的代码，在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区，那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起，并一直持续到进入临界区的线程离开。临界区在被释放后，其他线程可以继续抢占，并以此达到用原子方式操作共享资源的目的。<br><br>　　临界区在使用时以CRITICAL_SECTION结构对象保护共享资源，并分别用EnterCriticalSection（）和LeaveCriticalSection（）函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection（）的初始化后才能使用，而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用，共享资源依然有被破坏的可能。<br><br><img height=87 alt=thread01.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/thread01.jpg" width=178 border=0><br>图1 使用临界区保持线程同步<br><br>　　下面通过一段代码展示了临界区在保护多线程访问的共享资源中的作用。通过两个线程来分别对全局变量g_cArray[10]进行写入操作，用临界区结构对象g_cs来保持线程的同步，并在开启线程前对其进行初始化。为了使实验效果更加明显，体现出临界区的作用，在线程函数对共享资源g_cArray[10]的写入时，以Sleep（）函数延迟1毫秒，使其他线程同其抢占CPU的可能性增大。如果不使用临界区对其进行保护，则共享资源数据将被破坏（参见图1（a）所示计算结果），而使用临界区对线程保持同步后则可以得到正确的结果（参见图1（b）所示计算结果）。代码实现清单附下：<br><br></p>
<p>&#160;</p>
<p>&#160;</p>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// 临界区结构对象<br>CRITICAL_SECTION g_cs;<br>// 共享资源 <br>char g_cArray[10];<br>UINT ThreadProc10(LPVOID pParam)<br>{<br>　// 进入临界区<br>　EnterCriticalSection(&amp;g_cs);<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[i] = 'a';<br>　　Sleep(1);<br>　}<br>　// 离开临界区<br>　LeaveCriticalSection(&amp;g_cs);<br>　return 0;<br>}<br>UINT ThreadProc11(LPVOID pParam)<br>{<br>　// 进入临界区<br>　EnterCriticalSection(&amp;g_cs);<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[10 - i - 1] = 'b';<br>　　Sleep(1);<br>　}<br>　// 离开临界区<br>　LeaveCriticalSection(&amp;g_cs);<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnCriticalSection() <br>{<br>　// 初始化临界区<br>　InitializeCriticalSection(&amp;g_cs);<br>　// 启动线程<br>　AfxBeginThread(ThreadProc10, NULL);<br>　AfxBeginThread(ThreadProc11, NULL);<br>　// 等待计算完毕<br>　Sleep(300);<br>　// 报告计算结果<br>　CString sResult = CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　在使用临界区时，一般不允许其运行时间过长，只要进入临界区的线程还没有离开，其他所有试图进入此临界区的线程都会被挂起而进入到等待状态，并会在一定程度上影响。程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。如果进入了临界区却一直没有释放，同样也会引起其他线程的长时间等待。换句话说，在执行了EnterCriticalSection（）语句进入临界区后无论发生什么，必须确保与之匹配的LeaveCriticalSection（）都能够被执行到。可以通过添加结构化异常处理代码来确保LeaveCriticalSection（）语句的执行。虽然临界区同步速度很快，但却只能用来同步本进程内的线程，而不可用来同步多个进程中的线程。<br><br>　　MFC为临界区提供有一个CCriticalSection类，使用该类进行线程同步处理是非常简单的，只需在线程函数中用CCriticalSection类成员函数Lock（）和UnLock（）标定出被保护代码片段即可。对于上述代码，可通过CCriticalSection类将其改写如下：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// MFC临界区类对象<br>CCriticalSection g_clsCriticalSection;<br>// 共享资源 <br>char g_cArray[10];<br>UINT ThreadProc20(LPVOID pParam)<br>{<br>　// 进入临界区<br>　g_clsCriticalSection.Lock();<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[i] = 'a';<br>　　Sleep(1);<br>　}<br>　// 离开临界区<br>　g_clsCriticalSection.Unlock();<br>　return 0;<br>}<br>UINT ThreadProc21(LPVOID pParam)<br>{<br>　// 进入临界区<br>　g_clsCriticalSection.Lock();<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[10 - i - 1] = 'b';<br>　　Sleep(1);<br>　}<br>　// 离开临界区<br>　g_clsCriticalSection.Unlock();<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnCriticalSectionMfc() <br>{<br>　// 启动线程<br>　AfxBeginThread(ThreadProc20, NULL);<br>　AfxBeginThread(ThreadProc21, NULL);<br>　// 等待计算完毕<br>　Sleep(300);<br>　// 报告计算结果<br>　CString sResult = CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</td>
        </tr>
    </tbody>
</table>
<br><strong>管理事件内核对象<br><br></strong>　　在前面讲述线程通信时曾使用过事件内核对象来进行线程间的通信，除此之外，事件内核对象也可以通过通知操作的方式来保持线程的同步。对于前面那段使用临界区保持线程同步的代码可用事件对象的线程同步方法改写如下：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// 事件句柄<br>HANDLE hEvent = NULL;<br>// 共享资源 <br>char g_cArray[10];<br>&#8230;&#8230;<br>UINT ThreadProc12(LPVOID pParam)<br>{<br>　// 等待事件置位<br>　WaitForSingleObject(hEvent, INFINITE);<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[i] = 'a';<br>　　Sleep(1);<br>　}<br>　// 处理完成后即将事件对象置位<br>　SetEvent(hEvent);<br>　return 0;<br>}<br>UINT ThreadProc13(LPVOID pParam)<br>{<br>　// 等待事件置位<br>　WaitForSingleObject(hEvent, INFINITE);<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[10 - i - 1] = 'b';<br>　　Sleep(1);<br>　}<br>　// 处理完成后即将事件对象置位<br>　SetEvent(hEvent);<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnEvent() <br>{<br>　// 创建事件<br>　hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);<br>　// 事件置位<br>　SetEvent(hEvent);<br>　// 启动线程<br>　AfxBeginThread(ThreadProc12, NULL);<br>　AfxBeginThread(ThreadProc13, NULL);<br>　// 等待计算完毕<br>　Sleep(300);<br>　// 报告计算结果<br>　CString sResult = CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　在创建线程前，首先创建一个可以自动复位的事件内核对象hEvent，而线程函数则通过WaitForSingleObject（）等待函数无限等待hEvent的置位，只有在事件置位时WaitForSingleObject（）才会返回，被保护的代码将得以执行。对于以自动复位方式创建的事件对象，在其置位后一被WaitForSingleObject（）等待到就会立即复位，也就是说在执行ThreadProc12（）中的受保护代码时，事件对象已经是复位状态的，这时即使有ThreadProc13（）对CPU的抢占，也会由于WaitForSingleObject（）没有hEvent的置位而不能继续执行，也就没有可能破坏受保护的共享资源。在ThreadProc12（）中的处理完成后可以通过SetEvent（）对hEvent的置位而允许ThreadProc13（）对共享资源g_cArray的处理。这里SetEvent（）所起的作用可以看作是对某项特定任务完成的通知。<br><br>　　使用临界区只能同步同一进程中的线程，而使用事件内核对象则可以对进程外的线程进行同步，其前提是得到对此事件对象的访问权。可以通过OpenEvent（）函数获取得到，其函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>HANDLE OpenEvent(<br>　DWORD dwDesiredAccess, // 访问标志<br>　BOOL bInheritHandle, // 继承标志<br>　LPCTSTR lpName // 指向事件对象名的指针<br>);</td>
        </tr>
    </tbody>
</table>
<br>　　如果事件对象已创建（在创建事件时需要指定事件名），函数将返回指定事件的句柄。对于那些在创建事件时没有指定事件名的事件内核对象，可以通过使用内核对象的继承性或是调用DuplicateHandle（）函数来调用CreateEvent（）以获得对指定事件对象的访问权。在获取到访问权后所进行的同步操作与在同一个进程中所进行的线程同步操作是一样的。<br><br>　　如果需要在一个线程中等待多个事件，则用WaitForMultipleObjects（）来等待。WaitForMultipleObjects（）与WaitForSingleObject（）类似，同时监视位于句柄数组中的所有句柄。这些被监视对象的句柄享有平等的优先权，任何一个句柄都不可能比其他句柄具有更高的优先权。WaitForMultipleObjects（）的函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>DWORD WaitForMultipleObjects(<br>　DWORD nCount, // 等待句柄数<br>　CONST HANDLE *lpHandles, // 句柄数组首地址<br>　BOOL fWaitAll, // 等待标志<br>　DWORD dwMilliseconds // 等待时间间隔<br>);</td>
        </tr>
    </tbody>
</table>
<br>　　参数nCount指定了要等待的内核对象的数目，存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定，为TRUE时当所有对象都被通知时函数才会返回，为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject（）中的作用是完全一致的。如果等待超时，函数将返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某个值，则说明所有指定对象的状态均为已通知状态（当fWaitAll为TRUE时）或是用以减去WAIT_OBJECT_0而得到发生通知的对象的索引（当fWaitAll为FALSE时）。如果返回值在WAIT_ABANDONED_0与WAIT_ABANDONED_0+nCount-1之间，则表示所有指定对象的状态均为已通知，且其中至少有一个对象是被丢弃的互斥对象（当fWaitAll为TRUE时），或是用以减去WAIT_OBJECT_0表示一个等待正常结束的互斥对象的索引（当fWaitAll为FALSE时）。 下面给出的代码主要展示了对WaitForMultipleObjects（）函数的使用。通过对两个事件内核对象的等待来控制线程任务的执行与中途退出：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// 存放事件句柄的数组<br>HANDLE hEvents[2];<br>UINT ThreadProc14(LPVOID pParam)<br>{ <br>　// 等待开启事件<br>　DWORD dwRet1 = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);<br>　// 如果开启事件到达则线程开始执行任务<br>　if (dwRet1 == WAIT_OBJECT_0)<br>　{<br>　　AfxMessageBox("线程开始工作!");<br>　　while (true)<br>　　{<br>　　　for (int i = 0; i &lt; 10000; i++);<br>　　　// 在任务处理过程中等待结束事件 <br>　　　DWORD dwRet2 = WaitForMultipleObjects(2, hEvents, FALSE, 0);<br>　　　// 如果结束事件置位则立即终止任务的执行<br>　　　if (dwRet2 == WAIT_OBJECT_0 + 1)<br>　　　　break;<br>　　}<br>　}<br>　AfxMessageBox("线程退出!");<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnStartEvent() <br>{<br>　// 创建线程<br>　for (int i = 0; i &lt; 2; i++)<br>　　hEvents[i] = CreateEvent(NULL, FALSE, FALSE, NULL);<br>　　// 开启线程<br>　　AfxBeginThread(ThreadProc14, NULL);<br>　　// 设置事件0(开启事件)<br>　　SetEvent(hEvents[0]);<br>}<br>void CSample08View::OnEndevent() <br>{<br>　// 设置事件1(结束事件)<br>　SetEvent(hEvents[1]);<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　MFC为事件相关处理也提供了一个CEvent类，共包含有除构造函数外的4个成员函数PulseEvent（）、ResetEvent（）、SetEvent（）和UnLock（）。在功能上分别相当与Win32 API的PulseEvent（）、ResetEvent（）、SetEvent（）和CloseHandle（）等函数。而构造函数则履行了原CreateEvent（）函数创建事件对象的职责，其函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );</td>
        </tr>
    </tbody>
</table>
<br>　　按照此缺省设置将创建一个自动复位、初始状态为复位状态的没有名字的事件对象。封装后的CEvent类使用起来更加方便，图2即展示了CEvent类对A、B两线程的同步过程：<br><br><img height=97 alt=Thread02.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/Thread02.jpg" width=329 border=0><br>图2 CEvent类对线程的同步过程示意<br><br>　　B线程在执行到CEvent类成员函数Lock（）时将会发生阻塞，而A线程此时则可以在没有B线程干扰的情况下对共享资源进行处理，并在处理完成后通过成员函数SetEvent（）向B发出事件，使其被释放，得以对A先前已处理完毕的共享资源进行操作。可见，使用CEvent类对线程的同步方法与通过API函数进行线程同步的处理方法是基本一致的。前面的API处理代码可用CEvent类将其改写为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// MFC事件类对象<br>CEvent g_clsEvent;<br>UINT ThreadProc22(LPVOID pParam)<br>{<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[i] = 'a';<br>　　Sleep(1);<br>　}<br>　// 事件置位<br>　g_clsEvent.SetEvent();<br>　return 0;<br>}<br>UINT ThreadProc23(LPVOID pParam)<br>{<br>　// 等待事件<br>　g_clsEvent.Lock();<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[10 - i - 1] = 'b';<br>　　Sleep(1);<br>　}<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnEventMfc() <br>{<br>　// 启动线程<br>　AfxBeginThread(ThreadProc22, NULL);<br>　AfxBeginThread(ThreadProc23, NULL);<br>　// 等待计算完毕<br>　Sleep(300);<br>　// 报告计算结果<br>　CString sResult = CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</td>
        </tr>
    </tbody>
</table>
<br><strong>信号量内核对象<br><br></strong>　　信号量（Semaphore）内核对象对线程的同步方式与前面几种方法不同，它允许多个线程在同一时刻访问同一资源，但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore（）创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数，每增加一个线程对共享资源的访问，当前可用资源计数就会减1，只要当前可用资源计数是大于0的，就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目，不能在允许其他线程的进入，此时的信号量信号将无法发出。线程在处理完共享资源后，应在离开的同时通过ReleaseSemaphore（）函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。<br><br><img height=82 alt=thread03.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/thread03.jpg" width=308 border=0><br>图3 使用信号量对象控制资源<br><br>　　下面结合图例3来演示信号量对象对资源的控制。在图3中，以箭头和白色箭头表示共享资源所允许的最大资源计数和当前可用资源计数。初始如图（a）所示，最大资源计数和当前可用资源计数均为4，此后每增加一个对资源进行访问的线程（用黑色箭头表示）当前资源计数就会相应减1，图（b）即表示的在3个线程对共享资源进行访问时的状态。当进入线程数达到4个时，将如图（c）所示，此时已达到最大资源计数，而当前可用资源计数也已减到0，其他线程无法对共享资源进行访问。在当前占有资源的线程处理完毕而退出后，将会释放出空间，图（d）已有两个线程退出对资源的占有，当前可用计数为2，可以再允许2个线程进入到对资源的处理。可以看出，信号量是通过计数来对线程访问资源进行控制的，而实际上信号量确实也被称作Dijkstra计数器。<br><br>　　使用信号量内核对象进行线程同步主要会用到CreateSemaphore（）、OpenSemaphore（）、ReleaseSemaphore（）、WaitForSingleObject（）和WaitForMultipleObjects（）等函数。其中，CreateSemaphore（）用来创建一个信号量内核对象，其函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>HANDLE CreateSemaphore(<br>　LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性指针<br>　LONG lInitialCount, // 初始计数<br>　LONG lMaximumCount, // 最大计数<br>　LPCTSTR lpName // 对象名指针<br>); </td>
        </tr>
    </tbody>
</table>
<br>　　参数lMaximumCount是一个有符号32位值，定义了允许的最大资源计数，最大取值不能超过4294967295。lpName参数可以为创建的信号量定义一个名字，由于其创建的是一个内核对象，因此在其他进程中可以通过该名字而得到此信号量。OpenSemaphore（）函数即可用来根据信号量名打开在其他进程中创建的信号量，函数原型如下：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>HANDLE OpenSemaphore(<br>　DWORD dwDesiredAccess, // 访问标志<br>　BOOL bInheritHandle, // 继承标志<br>　LPCTSTR lpName // 信号量名<br>);</td>
        </tr>
    </tbody>
</table>
<br>　　在线程离开对共享资源的处理时，必须通过ReleaseSemaphore（）来增加当前可用资源计数。否则将会出现当前正在处理共享资源的实际线程数并没有达到要限制的数值，而其他线程却因为当前可用资源计数为0而仍无法进入的情况。ReleaseSemaphore（）的函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>BOOL ReleaseSemaphore(<br>　HANDLE hSemaphore, // 信号量句柄<br>　LONG lReleaseCount, // 计数递增数量<br>　LPLONG lpPreviousCount // 先前计数<br>);</td>
        </tr>
    </tbody>
</table>
<br>　　该函数将lReleaseCount中的值添加给信号量的当前资源计数，一般将lReleaseCount设置为1，如果需要也可以设置其他的值。WaitForSingleObject（）和WaitForMultipleObjects（）主要用在试图进入共享资源的线程函数入口处，主要用来判断信号量的当前可用资源计数是否允许本线程的进入。只有在当前可用资源计数值大于0时，被监视的信号量内核对象才会得到通知。<br><br>　　信号量的使用特点使其更适用于对Socket（套接字）程序中线程的同步。例如，网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限制，这时可以为没一个用户对服务器的页面请求设置一个线程，而页面则是待保护的共享资源，通过使用信号量对线程的同步作用可以确保在任一时刻无论有多少用户对某一页面进行访问，只有不大于设定的最大用户数目的线程能够进行访问，而其他的访问企图则被挂起，只有在有用户退出对此页面的访问后才有可能进入。下面给出的示例代码即展示了类似的处理过程：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// 信号量对象句柄<br>HANDLE hSemaphore;<br>UINT ThreadProc15(LPVOID pParam)<br>{ <br>　// 试图进入信号量关口<br>　WaitForSingleObject(hSemaphore, INFINITE);<br>　// 线程任务处理<br>　AfxMessageBox("线程一正在执行!");<br>　// 释放信号量计数<br>　ReleaseSemaphore(hSemaphore, 1, NULL);<br>　return 0;<br>}<br>UINT ThreadProc16(LPVOID pParam)<br>{ <br>　// 试图进入信号量关口<br>　WaitForSingleObject(hSemaphore, INFINITE);<br>　// 线程任务处理<br>　AfxMessageBox("线程二正在执行!");<br>　// 释放信号量计数<br>　ReleaseSemaphore(hSemaphore, 1, NULL);<br>　return 0;<br>}<br>UINT ThreadProc17(LPVOID pParam)<br>{ <br>　// 试图进入信号量关口<br>　WaitForSingleObject(hSemaphore, INFINITE);<br>　// 线程任务处理<br>　AfxMessageBox("线程三正在执行!");<br>　// 释放信号量计数<br>　ReleaseSemaphore(hSemaphore, 1, NULL);<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnSemaphore() <br>{<br>　// 创建信号量对象<br>　hSemaphore = CreateSemaphore(NULL, 2, 2, NULL);<br>　// 开启线程<br>　AfxBeginThread(ThreadProc15, NULL);<br>　AfxBeginThread(ThreadProc16, NULL);<br>　AfxBeginThread(ThreadProc17, NULL);<br>}</td>
        </tr>
    </tbody>
</table>
<br><img height=152 alt=thread04.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/thread04.jpg" width=242 border=0><br>图4 开始进入的两个线程<br><br><img height=152 alt=thread05.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/thread05.jpg" width=242 border=0><br>图5 线程二退出后线程三才得以进入<br><br>　　上述代码在开启线程前首先创建了一个初始计数和最大资源计数均为2的信号量对象hSemaphore。即在同一时刻只允许2个线程进入由hSemaphore保护的共享资源。随后开启的三个线程均试图访问此共享资源，在前两个线程试图访问共享资源时，由于hSemaphore的当前可用资源计数分别为2和1，此时的hSemaphore是可以得到通知的，也就是说位于线程入口处的WaitForSingleObject（）将立即返回，而在前两个线程进入到保护区域后，hSemaphore的当前资源计数减少到0，hSemaphore将不再得到通知，WaitForSingleObject（）将线程挂起。直到此前进入到保护区的线程退出后才能得以进入。图4和图5为上述代脉的运行结果。从实验结果可以看出，信号量始终保持了同一时刻不超过2个线程的进入。<br><br>　　在MFC中，通过CSemaphore类对信号量作了表述。该类只具有一个构造函数，可以构造一个信号量对象，并对初始资源计数、最大资源计数、对象名和安全属性等进行初始化，其原型如下：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );</td>
        </tr>
    </tbody>
</table>
<br>　　在构造了CSemaphore类对象后，任何一个访问受保护共享资源的线程都必须通过CSemaphore从父类CSyncObject类继承得到的Lock（）和UnLock（）成员函数来访问或释放CSemaphore对象。与前面介绍的几种通过MFC类保持线程同步的方法类似，通过CSemaphore类也可以将前面的线程同步代码进行改写，这两种使用信号量的线程同步方法无论是在实现原理上还是从实现结果上都是完全一致的。下面给出经MFC改写后的信号量线程同步代码：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// MFC信号量类对象<br>CSemaphore g_clsSemaphore(2, 2);<br>UINT ThreadProc24(LPVOID pParam)<br>{ <br>　// 试图进入信号量关口<br>　g_clsSemaphore.Lock();<br>　// 线程任务处理<br>　AfxMessageBox("线程一正在执行!");<br>　// 释放信号量计数<br>　g_clsSemaphore.Unlock();<br>　return 0;<br>}<br>UINT ThreadProc25(LPVOID pParam)<br>{<br>　// 试图进入信号量关口<br>　g_clsSemaphore.Lock();<br>　// 线程任务处理<br>　AfxMessageBox("线程二正在执行!");<br>　// 释放信号量计数<br>　g_clsSemaphore.Unlock();<br>　return 0;<br>}<br>UINT ThreadProc26(LPVOID pParam)<br>{<br>　// 试图进入信号量关口<br>　g_clsSemaphore.Lock();<br>　// 线程任务处理<br>　AfxMessageBox("线程三正在执行!");<br>　// 释放信号量计数<br>　g_clsSemaphore.Unlock();<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnSemaphoreMfc() <br>{<br>　// 开启线程<br>　AfxBeginThread(ThreadProc24, NULL);<br>　AfxBeginThread(ThreadProc25, NULL);<br>　AfxBeginThread(ThreadProc26, NULL);<br>}</td>
        </tr>
    </tbody>
</table>
<br><br><strong>互斥内核对象<br><br></strong>　　互斥（Mutex）是一种用途非常广泛的内核对象。能够保证多个线程对同一共享资源的互斥访问。同临界区有些类似，只有拥有互斥对象的线程才具有访问资源的权限，由于互斥对象只有一个，因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出，以便其他线程在获得后得以访问资源。与其他几种内核对象不同，互斥对象在操作系统中拥有特殊代码，并由操作系统来管理，操作系统甚至还允许其进行一些其他内核对象所不能进行的非常规操作。为便于理解，可参照图6给出的互斥内核对象的工作模型：<br><br><img height=78 alt=thread06.jpg src="http://www.cppblog.com/images/cppblog_com/andxie99/thread06.jpg" width=401 border=0><br>图6 使用互斥内核对象对共享资源的保护<br><br>　　图（a）中的箭头为要访问资源（矩形框）的线程，但只有第二个线程拥有互斥对象（黑点）并得以进入到共享资源，而其他线程则会被排斥在外（如图（b）所示）。当此线程处理完共享资源并准备离开此区域时将把其所拥有的互斥对象交出（如图（c）所示），其他任何一个试图访问此资源的线程都有机会得到此互斥对象。<br><br>　　以互斥内核对象来保持线程同步可能用到的函数主要有CreateMutex（）、OpenMutex（）、ReleaseMutex（）、WaitForSingleObject（）和WaitForMultipleObjects（）等。在使用互斥对象前，首先要通过CreateMutex（）或OpenMutex（）创建或打开一个互斥对象。CreateMutex（）函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>HANDLE CreateMutex(<br>　LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性指针<br>　BOOL bInitialOwner, // 初始拥有者<br>　LPCTSTR lpName // 互斥对象名<br>);</td>
        </tr>
    </tbody>
</table>
<br>　　参数bInitialOwner主要用来控制互斥对象的初始状态。一般多将其设置为FALSE，以表明互斥对象在创建时并没有为任何线程所占有。如果在创建互斥对象时指定了对象名，那么可以在本进程其他地方或是在其他进程通过OpenMutex（）函数得到此互斥对象的句柄。OpenMutex（）函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>HANDLE OpenMutex(<br>　DWORD dwDesiredAccess, // 访问标志<br>　BOOL bInheritHandle, // 继承标志<br>　LPCTSTR lpName // 互斥对象名<br>); </td>
        </tr>
    </tbody>
</table>
<br>　　当目前对资源具有访问权的线程不再需要访问此资源而要离开时，必须通过ReleaseMutex（）函数来释放其拥有的互斥对象，其函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>BOOL ReleaseMutex(HANDLE hMutex);</td>
        </tr>
    </tbody>
</table>
<br>　　其唯一的参数hMutex为待释放的互斥对象句柄。至于WaitForSingleObject（）和WaitForMultipleObjects（）等待函数在互斥对象保持线程同步中所起的作用与在其他内核对象中的作用是基本一致的，也是等待互斥内核对象的通知。但是这里需要特别指出的是：在互斥对象通知引起调用等待函数返回时，等待函数的返回值不再是通常的WAIT_OBJECT_0（对于WaitForSingleObject（）函数）或是在WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1之间的一个值（对于WaitForMultipleObjects（）函数），而是将返回一个WAIT_ABANDONED_0（对于WaitForSingleObject（）函数）或是在WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1之间的一个值（对于WaitForMultipleObjects（）函数）。以此来表明线程正在等待的互斥对象由另外一个线程所拥有，而此线程却在使用完共享资源前就已经终止。除此之外，使用互斥对象的方法在等待线程的可调度性上同使用其他几种内核对象的方法也有所不同，其他内核对象在没有得到通知时，受调用等待函数的作用，线程将会挂起，同时失去可调度性，而使用互斥的方法却可以在等待的同时仍具有可调度性，这也正是互斥对象所能完成的非常规操作之一。<br><br>　　在编写程序时，互斥对象多用在对那些为多个线程所访问的内存块的保护上，可以确保任何线程在处理此内存块时都对其拥有可靠的独占访问权。下面给出的示例代码即通过互斥内核对象hMutex对共享内存快g_cArray[]进行线程的独占访问保护。下面给出实现代码清单：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// 互斥对象<br>HANDLE hMutex = NULL;<br>char g_cArray[10];<br>UINT ThreadProc18(LPVOID pParam)<br>{<br>　// 等待互斥对象通知<br>　WaitForSingleObject(hMutex, INFINITE);<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[i] = 'a';<br>　　Sleep(1);<br>　}<br>　// 释放互斥对象<br>　ReleaseMutex(hMutex);<br>　return 0;<br>}<br>UINT ThreadProc19(LPVOID pParam)<br>{<br>　// 等待互斥对象通知<br>　WaitForSingleObject(hMutex, INFINITE);<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[10 - i - 1] = 'b';<br>　　Sleep(1);<br>　}<br>　// 释放互斥对象<br>　ReleaseMutex(hMutex);<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnMutex() <br>{<br>　// 创建互斥对象<br>　hMutex = CreateMutex(NULL, FALSE, NULL);<br>　// 启动线程<br>　AfxBeginThread(ThreadProc18, NULL);<br>　AfxBeginThread(ThreadProc19, NULL);<br>　// 等待计算完毕<br>　Sleep(300);<br>　// 报告计算结果<br>　CString sResult = CString(g_cArray);<br>　AfxMessageBox(sResult);<br>} </td>
        </tr>
    </tbody>
</table>
<br>　　互斥对象在MFC中通过CMutex类进行表述。使用CMutex类的方法非常简单，在构造CMutex类对象的同时可以指明待查询的互斥对象的名字，在构造函数返回后即可访问此互斥变量。CMutex类也是只含有构造函数这唯一的成员函数，当完成对互斥对象保护资源的访问后，可通过调用从父类CSyncObject继承的UnLock（）函数完成对互斥对象的释放。CMutex类构造函数原型为：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );</td>
        </tr>
    </tbody>
</table>
<br>　　该类的适用范围和实现原理与API方式创建的互斥内核对象是完全类似的，但要简洁的多，下面给出就是对前面的示例代码经CMutex类改写后的程序实现清单：<br><br>
<table width="100%" bgColor=#ffffff>
    <tbody>
        <tr>
            <td>// MFC互斥类对象<br>CMutex g_clsMutex(FALSE, NULL);<br>UINT ThreadProc27(LPVOID pParam)<br>{<br>　// 等待互斥对象通知<br>　g_clsMutex.Lock();<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[i] = 'a';<br>　　Sleep(1);<br>　}<br>　// 释放互斥对象<br>　g_clsMutex.Unlock();<br>　return 0;<br>}<br>UINT ThreadProc28(LPVOID pParam)<br>{<br>　// 等待互斥对象通知<br>　g_clsMutex.Lock();<br>　// 对共享资源进行写入操作<br>　for (int i = 0; i &lt; 10; i++)<br>　{<br>　　g_cArray[10 - i - 1] = 'b';<br>　　Sleep(1);<br>　}<br>　// 释放互斥对象<br>　g_clsMutex.Unlock();<br>　return 0;<br>}<br>&#8230;&#8230;<br>void CSample08View::OnMutexMfc() <br>{<br>　// 启动线程<br>　AfxBeginThread(ThreadProc27, NULL);<br>　AfxBeginThread(ThreadProc28, NULL);<br>　// 等待计算完毕<br>　Sleep(300);<br>　// 报告计算结果<br>　CString sResult = CString(g_cArray);<br>　AfxMessageBox(sResult);<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　<strong>小结</strong><br><br>　　线程的使用使程序处理更够更加灵活，而这种灵活同样也会带来各种不确定性的可能。尤其是在多个线程对同一公共变量进行访问时。虽然未使用线程同步的程序代码在逻辑上或许没有什么问题，但为了确保程序的正确、可靠运行，必须在适当的场合采取线程同步措施。</div>
<img src ="http://www.cppblog.com/niewenlong/aggbug/32784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2007-09-24 14:53 <a href="http://www.cppblog.com/niewenlong/archive/2007/09/24/32784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在VC中使用位图按钮</title><link>http://www.cppblog.com/niewenlong/archive/2007/08/13/29920.html</link><dc:creator>聂文龙</dc:creator><author>聂文龙</author><pubDate>Mon, 13 Aug 2007 09:26:00 GMT</pubDate><guid>http://www.cppblog.com/niewenlong/archive/2007/08/13/29920.html</guid><wfw:comment>http://www.cppblog.com/niewenlong/comments/29920.html</wfw:comment><comments>http://www.cppblog.com/niewenlong/archive/2007/08/13/29920.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/niewenlong/comments/commentRss/29920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/niewenlong/services/trackbacks/29920.html</trackback:ping><description><![CDATA[位图按钮的实现方法： &nbsp; <br>&nbsp; 首先，我们创建一个基于对话框的应用程序CmyDialog &nbsp; ； &nbsp; <br>&nbsp; &#921;．MFC的CBitmapButton类，这也是最简单的功能最强的位图按钮。我们可以采取如下的步骤： &nbsp; <br>&nbsp; 1． 为按钮指定唯一的按钮标题（此例子为OK按钮，这里设置按钮标题为OK）并选中Ownerdraw属性，然后在项目中加一些位图资源，并用名字标示这些资源而不要用数字ID，其ID分别为&#8221;OKU&#8221;、&#8221;OKD&#8221;、&#8221;OKF&#8221;、&#8221;OKX&#8221;（一定要加双引号），分别对应于按钮的&#8220;松开(Up)&#8221;、&#8220;按下(Down)&#8221;、&#8220;获得输入焦点(focused)&#8221;和&#8220;禁止(Disable)&#8221;状态。 &nbsp; <br>&nbsp; 2． 我们还要在对话框类中加入CBitmapButton &nbsp; m_aBmpBtn;数据成员。 &nbsp; <br>&nbsp; 3． 在初始化中为这个成员调用： &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8230; &nbsp; <br>&nbsp; m_aBmpBtn. &nbsp; AutoLoad(IDOK,this); &nbsp; <br>&nbsp; &#8230; &nbsp; <br>&nbsp; 点击编译按钮，成功后运行程序，哈哈，看看效果，我们的位图按钮已经建立了。 &nbsp; <br>&nbsp; /*如果以上方法不行请检查你的BITMAP &nbsp; 资源，APPSTUDIO中，"OKU"和 &nbsp; "OKD" &nbsp; 等的资源名称都是需要用引号引起来的， &nbsp; AutoLoad不成功，很可能就是由此产生的。 &nbsp; &nbsp; */ &nbsp; <br>&nbsp; 改变CANCLE按钮的标题，可以设置其标题为ICON或者BITMAP &nbsp; ：（这里我们演示了bitmap的用法，Icon按钮读者可以按照下面的代码处理） &nbsp; <br>&nbsp; Ⅱ．使用图标制作按钮 &nbsp; <br>&nbsp; 1． 打开ICON按钮的属性页，在Style中选中Icon &nbsp; 。 &nbsp; <br>&nbsp; 2． 在对话框类的头文件中定义成员变量（使用ClassWizard加入这个成员变量） &nbsp; <br>&nbsp; CButton &nbsp; m_ &nbsp; IconBtn；//对应于图标按钮 &nbsp; <br>&nbsp; 3． 创建相应的图标或者位图资源： &nbsp; <br>&nbsp; 图标资源：IDI_ICONBUTTON &nbsp; <br>&nbsp; 4．在初始化中加入如下代码： &nbsp; &nbsp; <br>&nbsp; &#8230; &nbsp; <br>&nbsp; //对应于图标按钮 &nbsp; <br>&nbsp; HICON &nbsp; hIcon=AfxGetApp()-&gt;LoadIcon(IDI_ &nbsp; ICONBUTTON); &nbsp; <br>&nbsp; m_IconBtn.SetIcon(hIcon); &nbsp; <br>&nbsp; &#8230; &nbsp; <br>&nbsp; 重新编译运行我们的程序，奇妙的图像按钮呈现在我们的眼前了。 &nbsp; <br>&nbsp; Ⅲ．使用位图制作按钮 &nbsp; <br>&nbsp; 1． 打开BITMAP按钮的属性页，在Style中选中Bitmap。 &nbsp; <br>&nbsp; 2． 对话框类的头文件中定义成员变量（使用ClassWizard加入这个成员变量） &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CButton &nbsp; m_IconBtn； &nbsp; <br>&nbsp; 3．创建位图资源： &nbsp; <br>&nbsp; 位图资源：IDB_BITMAPBUTTON &nbsp; <br>&nbsp; 4．在初始化中加入如下代码： &nbsp; &nbsp; <br>&nbsp; //对应于位图按钮 &nbsp; <br>&nbsp; &#8230; &nbsp; <br>&nbsp; HBITMAP &nbsp; hBmp=::LoadBitmap(AfxGetInstanceHandle(), &nbsp; <br>&nbsp; MAKEINTRESOURCE(IDB_ &nbsp; BITMAPBUTTON)); &nbsp; <br>&nbsp; m_BmpBtn.SetBitmap(hBmp);&nbsp;&nbsp; <br>
<img src ="http://www.cppblog.com/niewenlong/aggbug/29920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/niewenlong/" target="_blank">聂文龙</a> 2007-08-13 17:26 <a href="http://www.cppblog.com/niewenlong/archive/2007/08/13/29920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>