﻿<?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++博客-C++乐园</title><link>http://www.cppblog.com/killsound/</link><description>C/C++ 交流</description><language>zh-cn</language><lastBuildDate>Sun, 05 Apr 2026 16:20:23 GMT</lastBuildDate><pubDate>Sun, 05 Apr 2026 16:20:23 GMT</pubDate><ttl>60</ttl><item><title>linux下patch打补丁</title><link>http://www.cppblog.com/killsound/archive/2009/12/03/102463.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Thu, 03 Dec 2009 05:45:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2009/12/03/102463.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/102463.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2009/12/03/102463.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/102463.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/102463.html</trackback:ping><description><![CDATA[<table style="TABLE-LAYOUT: fixed; WIDTH: 100%">
    <tbody>
        <tr>
            <td>
            <div class=cnt id=blog_text><span>首先介绍一下</span><span>diff</span><span>和</span><span>patch</span><span>。在这里不会把</span><span>man</span><span>在线文档上所有的选项都介绍一下，那样也没有必要。在</span><span>99</span><span>％的时间里，我们只会用到几个选项。所以必须学会这几个选项。</span>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font face=宋体><span>1</span><span>、</span><span>diff</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font face=宋体><span>－－－－－－－－－－－－－－－－－－－－</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font face=宋体><span>NAME</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font face=宋体><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>diff - find differences between two files</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font face=宋体><span>SYNOPSIS</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font face=宋体><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>diff [options] from-file to-file</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font face=宋体><span>－－－－－－－－－－－－－－－－－－－－</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><font face=宋体><span>简单的说，</span><span>diff</span><span>的功能就是用来比较两个文件的不同，然后记录下来，也就是所谓的</span><span>diff</span><span>补丁。语法格式：</span><span>diff </span><span>【选项】</span></font><font face=宋体> <span style="COLOR: green">源文件（夹）</span></font><font face=宋体> <span style="COLOR: fuchsia">目的文件（夹）</span><span>，就是要给<span style="COLOR: green">源文件（夹）</span>打个补丁，使之变成<span style="COLOR: fuchsia">目的文件（夹）</span>，术语也就是&#8220;升级&#8221;。下面介绍三个最为常用选项：</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>-r </span><span>是一个递归选项，设置了这个选项，</span><span>diff</span><span>会将两个不同版本源代码目录中的所有对应文件全部都进行一次比较，包括子目录文件。</span></font><font face=宋体> </font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>-N </span><span>选项确保补丁文件将正确地处理已经创建或删除文件的情况。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>-u </span><span>选项以统一格式创建补丁文件，这种格式比缺省格式更紧凑些。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>2</span><span>、</span><span>patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>－－－－－－－－－－－－－－－－－－</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>NAME</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>patch - apply a diff file to an original</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>SYNOPSIS</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>patch [options] [originalfile [patchfile]]</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>but usually just</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>patch -pnum &lt;patchfile&gt;</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>－－－－－－－－－－－－－－－－－－</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>简单的说，</span><span>patch</span><span>就是利用</span><span>diff</span><span>制作的补丁来实现<span style="COLOR: green">源文件（夹）</span>和<span style="COLOR: fuchsia">目的文件（夹）</span>的转换。这样说就意味着你可以有<span style="COLOR: green">源文件（夹）</span>――</span><span>&gt;</span><span style="COLOR: fuchsia">目的文件（夹）</span><span>，也可以<span style="COLOR: fuchsia">目的文件（夹）</span>――</span><span>&gt;</span><span style="COLOR: green">源文件（夹）。</span><span>下面介绍几个最常用选项：</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>-p0 </span><span>选项要从当前目录查找目的文件（夹）</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>-p1 </span><span>选项</span><span style="COLOR: black">要忽略掉第一层目录，从当前目录开始查找。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><font face=宋体><span style="FONT-SIZE: 12pt; COLOR: olive"><font size=2>************************************************************</font></span></font></p>
            <span style="FONT-SIZE: 12pt; COLOR: olive">
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span style="COLOR: rgb(255,102,0)">在这里以实例说明：</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 12pt; COLOR: rgb(255,102,0)"><font face=宋体 size=2>--- old/modules/pcitable<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Mon Sep 27 11:03:56 1999</font></span></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 12pt; COLOR: rgb(255,102,0)"><font face=宋体 size=2>+++ new/modules/pcitable<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Tue Dec 19 20:05:41 2000</font></span></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 12pt; COLOR: rgb(255,102,0)"><font face=宋体 size=2>&nbsp;&nbsp;&nbsp; 如果使用参数-p0，那就表示从当前目录找一个叫做old的文件夹，在它下面寻找modules下的pcitable文件来执行patch操作。</font></span></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align=left><span style="FONT-SIZE: 12pt; COLOR: rgb(255,102,0)"><font face=宋体 size=2>&nbsp;&nbsp;&nbsp; 如果使用参数-p1，那就表示忽略第一层目录（即不管old），从当前目录寻找modules的文件夹，在它下面找pcitable。这样的前提是当前目 录必须为modules所在的目录。而diff补丁文件则可以在任意位置，只要指明了diff补丁文件的路径就可以了。当然，可以用相对路径，也可以用绝 对路径。不过我一般习惯用相对路径。</font></span></p>
            </span><font size=3><font face=宋体><span style="COLOR: olive">************************************************************</span> </font></font>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>-E<span> </span></span><span>选项说明如果发现了空文件，那么就删除它</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>-R<span> </span></span><span>选项说明在补丁文件中的</span><span>&#8220;</span><span>新</span><span>&#8221;</span><span>文件和</span><span>&#8220;</span><span>旧</span><span>&#8221;</span><span>文件现在要调换过来了（实际上就是给新版本打补丁，让它变成老版本）</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><font face=宋体><span>下面结合具体实例来分析和解决，分为两种类型：为单个文件打补丁和为文件夹内的多个文件打补丁。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>环境：在</span><span>RedHat 9.0</span><span>下面以</span><span>armlinux</span><span>用户登陆。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>目录树如下：</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- bootloader</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- debug</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- images</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- kernel</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- program</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- rootfiles</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- software</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- source</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- sysapps</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>|-- tmp</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>`-- tools</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>下面在</span><span>program</span><span>文件夹下面建立</span><span>patch</span><span>文件夹作为实验用，然后进入</span><span>patch</span><span>文件夹。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>一、为单个文件进行补丁操作</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>1</span><span>、建立测试文件</span><span>test0</span><span>、</span><span>test1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cat<span> </span>&gt;&gt;test0&lt;&lt;EOF</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; 111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; 111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; 111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; EOF</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ more test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cat &gt;&gt;test1&lt;&lt;EOF</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; 222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; 111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; 222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; 111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; EOF</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ more test1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>2</span><span>、使用</span><span>diff</span><span>创建补丁</span><span>test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ diff -uN test0 test1 &gt; test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: green">【注：因为单个文件，所以不需要</span><span style="COLOR: green">-r</span><span style="COLOR: green">选项。选项顺序没有关系，即可以是</span><span style="COLOR: green">-uN</span><span style="COLOR: green">，也可以是</span><span style="COLOR: green">-Nu</span><span style="COLOR: green">。】</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>test0<span> </span>test1<span> </span>test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ more test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span><span style="COLOR: rgb(255,153,0)">************************************************************</span></span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: olive">patch</span><span style="COLOR: olive">文件的结构</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: olive">补丁头</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: rgb(255,153,0)">补丁头是分别由</span><span style="COLOR: rgb(255,153,0)">---/+++</span><span style="COLOR: rgb(255,153,0)">开头的两行，用来表示要打补丁的文件。</span><span style="COLOR: rgb(255,153,0)">---</span><span style="COLOR: rgb(255,153,0)">开头表示旧文件，</span><span style="COLOR: rgb(255,153,0)">+++</span><span style="COLOR: rgb(255,153,0)">开头表示新文件。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: olive">一个补丁文件中的多个补丁</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: rgb(255,153,0)">一个补丁文件中可能包含以</span><span style="COLOR: rgb(255,153,0)">---/+++</span><span style="COLOR: rgb(255,153,0)">开头的很多节，每一节用来打一个补丁。所以在一个补丁文件中可以包含好多个补丁。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: olive">块</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: rgb(255,153,0)">块是补丁中要修改的地方。它通常由一部分不用修改的东西开始和结束。他们只是用来表示要修改的位置。他们通常以</span><span style="COLOR: rgb(255,153,0)">@@</span><span style="COLOR: rgb(255,153,0)">开始，结束于另一个块的开始或者一个新的补丁头。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: olive">块的缩进</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: rgb(255,153,0)">块会缩进一列，而这一列是用来表示这一行是要增加还是要删除的。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: olive">块的第一列</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: rgb(255,153,0)">+</span><span style="COLOR: rgb(255,153,0)">号表示这一行是要加上的。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: rgb(255,153,0)">-</span><span style="COLOR: rgb(255,153,0)">号表示这一行是要删除的。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: rgb(255,153,0)">没有加号也没有减号表示这里只是引用的而不需要修改。</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: rgb(255,153,0)">************************************************************</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span style="COLOR: green">***diff</span><span style="COLOR: green">命令会在补丁文件中记录这两个文件的首次创建时间，如下</span><span style="COLOR: green">***</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>--- test0<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2006-08-18 09:12:01.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+++ test1<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2006-08-18 09:13:09.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>@@ -1,3 +1,4 @@</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>-111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ patch -p0 &lt; test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>test0<span> </span>test1<span> </span>test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cat test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>3、可以去除补丁，恢复旧版本</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ patch -RE -p0 &lt; test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>test0<span> </span>test1<span> </span>test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cat test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>二、为多个文件进行补丁操作</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>1</span><span>、创建测试文件夹</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ mkdir prj0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cp test0 prj0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>prj0<span> </span>test0<span> </span>test1<span> </span>test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cd prj0/</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ cat &gt;&gt;prj0name&lt;&lt;EOF</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; --------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; prj0/prj0name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; --------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; EOF</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>prj0name<span> </span>test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ cat prj0name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>--------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>prj0/prj0name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>--------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ cd ..</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ mkdir prj1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cp test1 prj1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cd prj1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj1]$ cat &gt;&gt;prj1name&lt;&lt;EOF</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; ---------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; prj1/prj1name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; ---------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>&gt; EOF</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj1]$ cat prj1name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>---------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>prj1/prj1name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>---------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj1]$ cd ..</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>2</span><span>、创建补丁</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ diff -uNr prj0 prj1 &gt; prj1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ more prj1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>diff -uNr prj0/prj0name prj1/prj0name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>--- prj0/prj0name<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2006-08-18 09:25:11.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+++ prj1/prj0name<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>1970-01-01 08:00:00.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>@@ -1,3 +0,0 @@</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>---------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>-prj0/prj0name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>---------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>diff -uNr prj0/prj1name prj1/prj1name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>--- prj0/prj1name<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>1970-01-01 08:00:00.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+++ prj1/prj1name<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>2006-08-18 09:26:36.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>@@ -0,0 +1,3 @@</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+---------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+prj1/prj1name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+---------</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>diff -uNr prj0/test0 prj1/test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>--- prj0/test0<span> </span>2006-08-18 09:23:53.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+++ prj1/test0<span> </span>1970-01-01 08:00:00.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>@@ -1,3 +0,0 @@</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>-111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>-111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>-111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>diff -uNr prj0/test1 prj1/test1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>--- prj0/test1<span> </span>1970-01-01 08:00:00.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+++ prj1/test1<span> </span>2006-08-18 09:26:00.000000000 +0800</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>@@ -0,0 +1,4 @@</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+222222</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>+111111</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>prj0<span> </span>prj1<span> </span>prj1.patch<span> </span>test0<span> </span>test1<span> </span>test1.patch</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cp prj1.patch ./prj0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm patch]$ cd prj0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ patch -p1 &lt; prj1.patch </span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file prj0name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file prj1name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file test1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>prj1name<span> </span>prj1.patch<span> </span>test1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ patch -R -p1 &lt; prj1.patch </span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file prj0name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file prj1name</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>patching file test1</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>[armlinux@lqm prj0]$ ls</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span>prj0name<span> </span>prj1.patch<span> </span>test0</span></font></p>
            <p style="MARGIN: 0cm 0cm 0pt"><font face=宋体><span><span style="COLOR: red">－－－－－－－－－－－－－－－－－－－</span></span></font></p>
            <font face=宋体><span>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">总结一下：</span></p>
            </span><span>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">单个文件</span></p>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">diff &#8211;uN from-file to-file &gt;to-file.patch</span></p>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">patch &#8211;p0 &lt; to-file.patch</span></p>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">patch &#8211;RE &#8211;p0 &lt; to-file.patch</span></p>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">多个文件</span></p>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">diff &#8211;uNr from-docu to-docu<span> </span>&gt;to-docu.patch</span></p>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">patch &#8211;p1 &lt; to-docu.patch</span></p>
            <p style="MARGIN: 0cm 0cm 0pt"><span style="COLOR: red">patch &#8211;R &#8211;p1 &lt;to-docu.patch</span></p>
            </span></font></div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/killsound/aggbug/102463.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2009-12-03 13:45 <a href="http://www.cppblog.com/killsound/archive/2009/12/03/102463.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>setsockopt 设置socket 详细用法</title><link>http://www.cppblog.com/killsound/archive/2009/01/16/72138.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Fri, 16 Jan 2009 01:36:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2009/01/16/72138.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/72138.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2009/01/16/72138.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/72138.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/72138.html</trackback:ping><description><![CDATA[<p><strong><font color=#ff0000 size=5>1.</font></strong>closesocket（一般不会立即关闭而经历TIME_WAIT的过程）后想继续重用该socket：<br>BOOL bReuseaddr=TRUE;<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&amp;bReuseaddr,sizeof(BOOL));</p>
<p><br><strong><font color=#ff0000 size=5>2.</font></strong> 如果要已经处于连接状态的soket在调用closesocket后强制关闭，不经历<br>TIME_WAIT的过程：<br>BOOL bDontLinger = FALSE;<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&amp;bDontLinger,sizeof(BOOL));</p>
<p><br><strong><font color=#ff0000 size=5>3.</font></strong>在send(),recv()过程中有时由于网络状况等原因，发收不能预期进行,而设置收发时限：<br>int nNetTimeout=1000;//1秒<br>//发送时限<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(socket，SOL_S0CKET,SO_SNDTIMEO，(char *)&amp;nNetTimeout,sizeof(int));<br>//接收时限<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(socket，SOL_S0CKET,SO_RCVTIMEO，(char *)&amp;nNetTimeout,sizeof(int));</p>
<p><br><strong><font color=#ff0000 size=5>4.</font></strong>在send()的时候，返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节<br>(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K)；在实际的过程中发送数据<br>和接收数据量比较大，可以设置socket缓冲区，而避免了send(),recv()不断的循环收发：<br>// 接收缓冲区<br>int nRecvBuf=32*1024;//设置为32K<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(s,SOL_SOCKET,SO_RCVBUF,(const char*)&amp;nRecvBuf,sizeof(int));<br>//发送缓冲区<br>int nSendBuf=32*1024;//设置为32K<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(s,SOL_SOCKET,SO_SNDBUF,(const char*)&amp;nSendBuf,sizeof(int));</p>
<p><br><strong><font color=#ff0000 size=5>5.</font></strong> 如果在发送数据的时，希望不经历由系统缓冲区到socket缓冲区的拷贝而影响<br>程序的性能：<br>int nZero=0;<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(socket，SOL_S0CKET,SO_SNDBUF，(char *)&amp;nZero,sizeof(nZero));</p>
<p><br><font color=#ff0000 size=5><strong>6.</strong></font>同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区)：<br>int nZero=0;<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(socket，SOL_S0CKET,SO_RCVBUF，(char *)&amp;nZero,sizeof(int));</p>
<p><br><font color=#ff0000 size=5><strong>7.</strong></font>一般在发送UDP数据报的时候，希望该socket发送的数据具有广播特性：<br>BOOL bBroadcast=TRUE;<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(s,SOL_SOCKET,SO_BROADCAST,(const char*)&amp;bBroadcast,sizeof(BOOL));</p>
<p><br><strong><font color=#ff0000 size=5>8.</font></strong>在client连接服务器过程中，如果处于非阻塞模式下的socket在connect()的过程中可<br>以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的<br>作用，在阻塞的函数调用中作用不大)<br>BOOL bConditionalAccept=TRUE;<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&amp;bConditionalAccept,sizeof(BOOL));</p>
<p><br><font size=5><strong><font color=#ff0000>9</font></strong>.</font>如果在发送数据的过程中(send()没有完成，还有数据没发送)而调用了closesocket(),以前我们<br>一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了，如何设置让程序满足具体<br>应用的要求(即让没发完的数据发送出去后在关闭socket)？<br>struct linger {<br>u_short l_onoff;<br>u_short l_linger;<br>};<br>linger m_sLinger;<br>m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)<br>// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;<br>m_sLinger.l_linger=5;//(容许逗留的时间为5秒)<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>(s,SOL_SOCKET,SO_LINGER,(const char*)&amp;m_sLinger,sizeof(linger));</p>
<p>///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// </p>
<p>设置套接口的选项。<br><br>&nbsp;&nbsp; #include &lt;winsock.h&gt;<br><br>&nbsp;&nbsp; int PASCAL FAR <strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>( SOCKET s, int level, int optname,<br>&nbsp;&nbsp; const char FAR* optval, int optlen);<br><br>&nbsp;&nbsp; s：标识一个套接口的描述字。<br>&nbsp;&nbsp; level：选项定义的层次；目前仅支持SOL_SOCKET和IPPROTO_TCP层次。<br>&nbsp;&nbsp; optname：需设置的选项。<br>&nbsp;&nbsp; optval：指针，指向存放选项值的缓冲区。<br>&nbsp;&nbsp; optlen：optval缓冲区的长度。<br><br>注释：<br>&nbsp;&nbsp;<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项，但本函数仅定义了最高的&#8220;套接口&#8221;层次上的选项。选项影响套接口的操作，诸如加急数据是否在普通数据流中接收，广播数据是否可以从套接口发送等等。<br>&nbsp;&nbsp; 有两种套接口的选项：一种是布尔型选项，允许或禁止一种特性；另一种是整形或结构选项。允许一个布尔型选项，则将optval指向非零整形数；禁止一个选项optval指向一个等于零的整形数。对于布尔型选项，optlen应等于sizeof(int)；对其他选项，optval指向包含所需选项的整形数或结构，而optlen则为整形数或结构的长度。SO_LINGER选项用于控制下述情况的行动：套接口上有排队的待发送数据，且closesocket()调用已执行。参见closesocket()函数中关于SO_LINGER选项对closesocket()语义的影响。应用程序通过创建一个linger结构来设置相应的操作特性：<br>&nbsp;&nbsp; struct linger {<br>int l_onoff;<br>int l_linger;<br>&nbsp;&nbsp; };<br>&nbsp;&nbsp; 为了允许SO_LINGER，应用程序应将l_onoff设为非零，将l_linger设为零或需要的超时值（以秒为单位），然后调用<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>()。为了允许SO_DONTLINGER（亦即禁止SO_LINGER），l_onoff应设为零，然后调用<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>()。<br>&nbsp;&nbsp; 缺省条件下，一个套接口不能与一个已在使用中的本地地址捆绑（参见bind()）。但有时会需要&#8220;重用&#8221;地址。因为每一个连接都由本地地址和远端地址的组合唯一确定，所以只要远端地址不同，两个套接口与一个地址捆绑并无大碍。为了通知WINDOWS套接口实现不要因为一个地址已被一个套接口使用就不让它与另一个套接口捆绑，应用程序可在bind()调用前先设置SO_REUSEADDR选项。请注意仅在bind()调用时该选项才被解释；故此无需（但也无害）将一个不会共用地址的套接口设置该选项，或者在bind()对这个或其他套接口无影响情况下设置或清除这一选项。<br>&nbsp;&nbsp; 一个应用程序可以通过打开SO_KEEPALIVE选项，使得WINDOWS套接口实现在TCP连接情况下允许使用&#8220;保持活动&#8221;包。一个WINDOWS套接口实现并不是必需支持&#8220;保持活动&#8221;，但是如果支持的话，具体的语义将与实现有关，应遵守RFC1122&#8220;Internet主机要求－通讯层&#8221;中第4.2.3.6节的规范。如果有关连接由于&#8220;保持活动&#8221;而失效，则进行中的任何对该套接口的调用都将以WSAENETRESET错误返回，后续的任何调用将以WSAENOTCONN错误返回。<br>&nbsp;&nbsp; TCP_NODELAY选项禁止Nagle算法。Nagle算法通过将未确认的数据存入缓冲区直到蓄足一个包一起发送的方法，来减少主机发送的零碎小数据包的数目。但对于某些应用来说，这种算法将降低系统性能。所以TCP_NODELAY可用来将此算法关闭。应用程序编写者只有在确切了解它的效果并确实需要的情况下，才设置TCP_NODELAY选项，因为设置后对网络性能有明显的负面影响。TCP_NODELAY是唯一使用IPPROTO_TCP层的选项，其他所有选项都使用SOL_SOCKET层。<br>&nbsp;&nbsp; 如果设置了SO_DEBUG选项，WINDOWS套接口供应商被鼓励（但不是必需）提供输出相应的调试信息。但产生调试信息的机制以及调试信息的形式已超出本规范的讨论范围。<br>&nbsp;&nbsp;<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>()支持下列选项。其中&#8220;类型&#8221;表明optval所指数据的类型。<br>选项 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 类型&nbsp;&nbsp; 意义<br>SO_BROADCAST BOOL 允许套接口传送广播信息。<br>SO_DEBUG BOOL 记录调试信息。<br>SO_DONTLINER BOOL 不要因为数据未发送就阻塞关闭操作。设置本选项相当于将SO_LINGER的l_onoff元素置为零。<br>SO_DONTROUTE BOOL 禁止选径；直接传送。<br>SO_KEEPALIVE BOOL 发送&#8220;保持活动&#8221;包。<br>SO_LINGER struct linger FAR*&nbsp;&nbsp; 如关闭时有未发送数据，则逗留。<br>SO_OOBINLINE BOOL 在常规数据流中接收带外数据。<br>SO_RCVBUF int 为接收确定缓冲区大小。<br>SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑（参见bind()）。<br>SO_SNDBUF int 指定发送缓冲区大小。<br>TCP_NODELAY BOOL 禁止发送合并的Nagle算法。<br><br>&nbsp;&nbsp;<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>()不支持的BSD选项有：<br>选项名 &nbsp;&nbsp; 类型 意义<br>SO_ACCEPTCONN BOOL 套接口在监听。<br>SO_ERROR int 获取错误状态并清除。<br>SO_RCVLOWAT int 接收低级水印。<br>SO_RCVTIMEO int 接收超时。<br>SO_SNDLOWAT int 发送低级水印。<br>SO_SNDTIMEO int 发送超时。<br>SO_TYPE &nbsp;&nbsp;&nbsp; int 套接口类型。<br>IP_OPTIONS &nbsp;&nbsp; 在IP头中设置选项。<br><br>返回值：<br>&nbsp;&nbsp; 若无错误发生，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">setsockopt</strong>()返回0。否则的话，返回SOCKET_ERROR错误，应用程序可通过WSAGetLastError()获取相应错误代码。<br><br>错误代码：<br>&nbsp;&nbsp; WSANOTINITIALISED：在使用此API之前应首先成功地调用WSAStartup()。<br>&nbsp;&nbsp; WSAENETDOWN：WINDOWS套接口实现检测到网络子系统失效。<br>&nbsp;&nbsp; WSAEFAULT：optval不是进程地址空间中的一个有效部分。<br>&nbsp;&nbsp; WSAEINPROGRESS：一个阻塞的WINDOWS套接口调用正在运行中。<br>&nbsp;&nbsp; WSAEINVAL：level值非法，或optval中的信息非法。<br>&nbsp;&nbsp; WSAENETRESET：当SO_KEEPALIVE设置后连接超时。<br>&nbsp;&nbsp; WSAENOPROTOOPT：未知或不支持选项。其中，SOCK_STREAM类型的套接口不支持SO_BROADCAST选项，SOCK_DGRAM类型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项。<br>&nbsp;&nbsp; WSAENOTCONN：当设置SO_KEEPALIVE后连接被复位。<br>&nbsp;&nbsp; WSAENOTSOCK：描述字不是一个套接口。<br><br>参见：<br>&nbsp;&nbsp; bind(), getsockopt(), ioctlsocket(), socket(), WSAAsyncSelect().</p>
<p>copy from:http://blog.csdn.net/qinmi/archive/2007/03/07/1523081.aspx</p>
<img src ="http://www.cppblog.com/killsound/aggbug/72138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2009-01-16 09:36 <a href="http://www.cppblog.com/killsound/archive/2009/01/16/72138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动态改变Dialog中IDC_STATIC的文字及颜色</title><link>http://www.cppblog.com/killsound/archive/2008/09/18/62149.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Thu, 18 Sep 2008 05:27:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2008/09/18/62149.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/62149.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2008/09/18/62149.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/62149.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/62149.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/killsound/archive/2008/09/18/62149.html'>阅读全文</a><img src ="http://www.cppblog.com/killsound/aggbug/62149.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2008-09-18 13:27 <a href="http://www.cppblog.com/killsound/archive/2008/09/18/62149.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UPnP协议简介</title><link>http://www.cppblog.com/killsound/archive/2007/12/19/39054.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Wed, 19 Dec 2007 08:47:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2007/12/19/39054.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/39054.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2007/12/19/39054.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/39054.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/39054.html</trackback:ping><description><![CDATA[<p>UPnP协议<br>统一即插即用英文是Universal Plug and Play，缩写为UPnP。要说计算机外设的即插即用(Plug and Play（缩写PnP）)，大家可能很熟悉，但对统一即插即用，多数人会感到是一头雾水。由于windows xp加入对UPnP的支持，并且被查出存在很严重的安全问题，所以，一时间，使得UPnP名声大噪。巧的是，本人原来查阅过关于UPnP的技术白皮书，而且也较为详细地看了关于此次发现的安全缺陷的介绍。因此，趁着这个机会，将UPnP以及引起安全缺陷的详情披露出来。</p>
<p>一、 UPnP是用来干什么的？</p>
<p>网络发展到现在，已经可以使我们在网上冲浪、收发邮件、听到远方传送来的声音、搜索感兴趣的内容、下载软件、点播节目、即时聊天&#8230;&#8230;实现的功能好像已经不少，但，人的欲望无止境，享福人还想更享福，还有许多目标没有达到：例如，怎样才能使我们在网络上，像平时用遥控器那样，操作空调器、电风扇、厨房电器，或网络远端的电器设备呢？如何利用网络上的计算机资源，使这种&#8220;遥控&#8221;更具智能化？甚至，将一系列相关的控制写到一个脚本中，以便用户定制自己所喜爱的控制流程&#8230;&#8230;实现诸如此类的效果，将是有巨大需求的应用技术。如果实现通过网络用UPnP控制家用设备，将给我们的生活带来很大的方便和很多新的体验。例如：</p>
<p>1.你在下班之前，或在回去的路上，就可以先打开家里的空调器和厨房设备，等进入家门，立刻就是一个温度宜人的环境――厨房里的饭也做好了。房间温度的高低和厨房内煮饭的过程，都是根据事先设计好的&#8220;脚本&#8221;程序进行的，绝对可靠。</p>
<p>2.你若是一位上档次的音乐发烧者，肯定对聆听音乐的环境要求很严：音箱位置高低、音量大小、灯光明暗、窗帘拉不拉上都有讲究。手动控制随好，毕竟不方便。你要使用上UPnP，一切都会为你代劳。还能将你习惯的音响音量、灯光亮度、音箱的高度等等，以你认为最佳的参数写到执行脚本中，以后可以都以此为准。如果你拥有自己的专门听音室，只要你打开听音室的门，上述的环境就会立刻设置好。曲终人散，只管放心离开好了，UPnP系统会自己关闭音响，熄灭电灯，拉上窗帘。</p>
<p>3.你人在办公室，心里却放不下家里的孩子。用上UPnP，只要在家里安装摄像头，建立好与网络的连接。在办公室内，启用桌面电脑的WEBTV，连通网络后，可以即时监视孩子在家里的一举一动。</p>
<p>凡此种种的方便和诱人之处还很多，不胜枚举。</p>
<p>其实，这已经不是科学幻想、也不是专家预言。目前用UPnP协议就可以实现这些操作！这正是windows xp系统急于加入UPnP的原因。正因为UPnP是一个协议，UPnP的使用可跨越各种操作系统平台，开发应用程序也没有开发语言的局限。可工作于各种形式的网络结构。且仅以现在的网络设施为基础，仅仅加上这个UPnP协议，既不用添加新的设施，也不用重新架设网络介质就可以投入使用！</p>
<p>UPnP协议具有下述特色：</p>
<p>1. 以网络为应用环境，不考虑&#8220;孤岛&#8221;中的计算机。</p>
<p>2. 以TCP/IP和整个Internet为基础。这样是&#8220;中立&#8221;的，不依附于任何操作系统或应用程序，不使用特定的API函数，不受程序设计语言的局限。可以无缝地接入传统网络。</p>
<p>3. 设备可以动态地进入网络中，随后获得IP地址，&#8220;学习&#8221; 或查找自己应当进行的操作和服务的信息；&#8220;感知&#8221;别的设备是否存在以及它们的作用和当前的状态 。所有这些，都应当是可自动完成的。</p>
<p>4. 每个设备都可读取属于自己的、特定的状态和参数；完成控制操作后应当发出&#8220;操作完成&#8221;的响应信号。如果失败，则应发出控制失败的信号。</p>
<p>二、UPnP协议的层：</p>
<p>UPnP协议的最终目的，是建立一个可用的设备模型， 因篇幅这里不对整个结构进行详细的分析，但你应当记住下面的主要特征：</p>
<p>1. UPnP是一个多层协议构成的框架体系，每一层都以相邻的下层为基础，同时又是相邻上层的基础。直至达到应用层为止。该图中的最下面是就是IP和TCP，共两层，负责设备的IP地址。</p>
<p>2. 三层是HTTP、HTTPU、HTTPMU，这一层，大家应当是熟悉的，属于传送协议层。传送的是内容都经过&#8220;封装&#8221;后，存放在特定的XML文件中的。对应的SSDP、GENA、SOAP指的是保存在XML文件中的数据格式。到这一层，已经解决了UPnP设备的IP地址和传送信息问题。</p>
<p>3. 第四层是UPnP设备体系定义，仅仅是一个抽象的、公用的设备模型。任何UPnP设备都必须使用这一层。</p>
<p>4. 第五层是UPnP论坛的各个专业委员会的设备定义层，在这个论坛中，不同电器设备由不同的专业委员会定义，例如：电视委员会只负责定义网络电视设备部分，空调器委员会只负责定义网络空调设备部分&#8230;&#8230;依此类推。所有的不同类型的设备都被定义成一个专门的架构或者模板，供建立设备的时候使用。可以推知，进入这一层，设备已经被指定了明确用途。当然，这些都必须遵守标准化的规范。从目前看，UPnP已经可以支持大部分的设备：从电脑、电脑外设，移动设备和家用消费类电子设备等等，无所不包，随着这个体系的普及，将可能有更多的厂家承认这一标准，最终，可能演化为公认的行业标准。</p>
<p>5. 最上层，也就是应用层，由UPnP设备制造厂商定义的部分。这一层的信息是由设备制造厂商来&#8220;填充&#8221; 的，这部分一般有设备厂商提供的、对设备控制和操作的底层代码，然后，就是名称序列号呀，厂商信息之类的东西。</p>
<p>三、协议内部的详细情况</p>
<p>仅仅有这样五层UPnP协议，也只不过有了一个共同遵守的框架，实际的UPnP系统究竟是如何构成的呢？</p>
<p>完整的UPnP服务系统由支持UPnP的网络和符合UPnP规范的设备共同构成的。</p>
<p>整个系统是由设备、服务、和控制指针三部分所构成。</p>
<p>设备：</p>
<p>这里是指符合UPnP规范的设备。一个UPnP设备可以看成一个包含服务并嵌套了常规设备的&#8220;容器&#8221; 。例如，一个UPnP的VCR（录像机）设备可以包含磁带传送服务、调谐服务和时钟服务。就是说，UPnP之下的设备不能仅仅理解为硬件意义上的设备，而应当包括服务功能。</p>
<p>不同种类的UPnP设备将关联不同的设置、服务和嵌入设备。如打印机和VCR属于不同用途的设备，服务就不可能定义成一样的。</p>
<p>服务：</p>
<p>设备执行用户请求的控制过程，可划分成一个个很小的阶段或单位，每个单位就称为一个服务。每一个服务，对外都表现为具体的行为和模式，而行为和模式又可以用状态和变量值进行描述。只要可以用数值描述，在计算机里面就容易处理了。例如，模仿一个时钟，它只有一个工作模式：这个模式就是模拟并显示当前的时间。而一个时钟的行为共有两种（也只有两种）：</p>
<p>1. 设置时间（用来&#8220;即平时说的对表&#8221;）.</p>
<p>2. 得到时间（用于显示时间）。</p>
<p>其它设备服务，也是用这样思路来描述和定义的，一个设备也可以被定义多个服务。不论是设备的定义信息和服务的描述信息，都保存在一个XML文件中，这个文件也是UPnP协议构成的一部分。当设备建立和使用服务的时候，XML文件可以与它们进行关联。</p>
<p>XML文件中还有一个很关键的&#8220;状态表&#8221;，状态表可进一步分为&#8220;服务状态表&#8221;和&#8220;事件状态表&#8221;。整个UPnP设备运行的全过程内，状态表贯穿始终，当设备状态改变的时候，例如发生参数变化或状态刷新的时候，立即就在&#8220;状态表&#8221;中反映出来。如控制服务器在接收到设置时间的行为请求时，就立即执行请求（对时操作），并给出响应，同时更新状态表中的有关数据。相应地，事件服务器负责向对此事件感兴趣的设备公布所发生的状态改变。例如，一个火灾事件发生后，事件服务器就向火灾报警器发布这个事件，导致报警器动作产生报警信号。</p>
<p>控制指针：</p>
<p>在UPnP网络中，用户请求设备执行的控制是通过控制指针实现的，控制指针首先是一个有能力控制别的设备的控制者，还要具有在网络中 &#8220;发现&#8221;控制目标的能力。在发现（控制目标）之后，控制指针应当：</p>
<p>①取得设备的描述信息并得到所关联的服务列表。</p>
<p>②取得相关服务的描述。</p>
<p>③调用控制服务行为。</p>
<p>④确定服务的事件 &#8220;源&#8221;，不论何时，只要服务状态发生改变，事件服务器会立即向控制指针发送一个事件信息。</p>
<p>从上面说到的各种信息，都保存在XML文件中，不同用途的信息，格式不同。保证可以各取所需，不会混淆。</p>
<p>那么，UPnP的完整工作过程是怎样的呢？</p>
<p>UPnP在控制指针和被控制设备之间提供通讯功能。而网络介质、TCP/IP协议、HTTP仅提供基本的连接和IP地址分配。整个工作过程需要处理六个方面的内容，即地址分配、发现设备、对设备的描述、设备控制、设备事件、设备表达。</p>
<p>地址问题：</p>
<p>地址是整个UPnP系统工作的基础条件，每个设备都应当是DHCP（Dynamic Host Configuration Protocol 动态主机配置协议）的客户。当设备首次与网络建立连接后，利用DHCP服务，使设备得到一个IP地址。这个IP地址可以是DHCP系统指定的，也可以是由设备选择的，当然，有能力自己选择IP地址的设备，必然是那些&#8220;聪明&#8221;的设备才行！这也就是所谓的&#8220;自动&#8221;IP地址。</p>
<p>如果遇到本地DHCP管理范围之外的IP地址请求，还需要解决&#8220;友好设备&#8221;</p>
<p>的地址分配问题，这个问题通常由域名服务器来解决。</p>
<p>发现设备：</p>
<p>可分成两种情况，一种是在有控制请求之后，在当前的网络中查找有无对应的可用设备；另一种情况是某一设备接入网络、取得IP地址之后，就开始向网络&#8220;广播&#8221;自己已经进入网络，即寻找控制请求。</p>
<p>设备的描述：</p>
<p>简单说，这是声明&#8220;自己&#8221;是什么样的设备，例如名称、制造厂商、序列号码等等。刚开始&#8220;发现&#8221;设备后，控制指针对这个设备的&#8220;了解&#8221;还很少，需要依据ULR找到该设备的描述文件，从这些文件中读取更多的描述信息。描述信息的范围很广，一般都是由设备的制造厂商提供的。主要的描述项目有：控制的模式名称和模式号码、设备序列号、制造厂商名称、厂商的WEB的ULR等等。这些一般都存放在特定的XML文件中；</p>
<p>设备控制：</p>
<p>控制指针找到设备描述之后，会从描述中&#8220;提炼&#8221;出要进行的操作并获悉所有的服务；对每个UPnP设备来说，这些描述必须是很确切、很详细的，描述中可能包含有命令或行为列表、服务响应信息、用到的参数等等。对于服务的每个行为，也伴有描述信息：主要是整个服务进行期间的变量、变量的数据类型、可用的取值范围和事件的特征。</p>
<p>要控制某个设备，控制指针必须先发送一个控制行为请求，要求设备开始服务，然后再按设备的ULR发送相应的控制消息，控制消息就是放置在XML文件中的那些SOAP格式的信息。最后，服务会返回响应信息，指出服务是成功或是失败。</p>
<p>设备事件：</p>
<p>在服务进行的整个时间内，只要变量值发生了变化或者模式的状态发生了改变，就产生了一个事件，系统将修改上述提到的事件列表的内容。随之，事件服务器把事件向整个网络进行广播。另一方面，控制指针也可以事先向事件服务器预约事件信息，保证将该控制指针感兴趣的事件及时准确地传送过来。</p>
<p>广播或预约事件，传送的都是事件消息，事件消息也放在XML文件中，使用的格式是GENA。</p>
<p>设备投入工作之前的准备―――初始化过程，也是一个事件，初始化需要的各种信息也是用事件消息传送的。包括的内容主要是：变量初始值，模式的初始状态等等。</p>
<p>设备表达：</p>
<p>只要得到了设备的ULR，就可以取得该设备表达页面的ULR，然后可以将此表达纳入用户的本地浏览器上。这部分还包括与用户对话的界面，以及与用户进行会话的处理。</p>
<p>整个UPnP系统，是在&#8220;中枢神经&#8221;的指挥下协同工作的。其大致情形如下：</p>
<p>凡是具备IP地址的的设备都必须直接使用网络的IP地址，但有些设备可能并不具备直接使用网络IP地址的能力，例如，电灯开关的控制就是这样，这是非IP设备；非IP设备通过网桥（UPnP Bridge）来与控制指针交换信息。</p>
<p>直接使用IP地址的有：控制指针（可在口袋电脑和远程设备上发出控制）、本地设备，例如VCR和时钟；以及网桥。非IP设备有所谓轻设备（如温度控制器）和非UPnP的设备（如电灯控制开关等）。</p>
<p>上述介绍属于硬件方面，下面再说作为控制灵魂的软件：</p>
<p>在上面的叙述中，多次提到用XML文件存放需要的信息，因为无论是控制指针或设备服务，都需要很多信息，有读出的，有传出的，UPnP协议约定这些都存放在特定的文件XML中。用途不同的信息，在XML文件中的格式不同。所以，相关的XML文件是控制服务的灵魂。</p>
<p>四、关于UPnP隐藏的安全缺缺陷：</p>
<p>这次发现的安全缺陷共有两个，其中第一个缺陷是对缓冲区（Buffer）的使用没有进行检查和限制。外部的攻击者，可以通过这里取得整个系统的控制特权！由于UPnp功能必须使用计算机的端口来进行工作，取得控制权的攻击者，还有可能利用这些端口，达到攻击者的目的。这个缺陷导致的后果很严重，不论那个版本的windows 系统，只要运行UPnP，就都存在这个危险！但严格地说，这并不完全是UPnP技术本身的问题，更多的是程序设计的疏忽。</p>
<p>第二个缺陷就与UPnP的工作机理有关系了！</p>
<p>该缺陷存在于UPnP工作时的&#8220;设备发现&#8221;阶段。发现设备可以分为两种情况：如果某个具备UPnP功能的计算机引导成功并连接到网络上，就会立刻向网络发出&#8220;广播&#8221;，向网络上的UPnP设备通知自己已经准备就绪，在程序设计这一级别上看，该广播内容就是一个M-SEARCH（消息）指示。该广播将被&#8220;声音所及&#8221;范围之内的所有设备所&#8220;听到&#8221;。并向该计算机反馈自己的有关信息，以备随后进行控制之用。</p>
<p>相类似，如果某个设备刚刚连接到网络上，也会向网络发出&#8220;通知&#8221;，表示自己准备就绪，可以接受来自网络的控制，在程序设计这一级别上看，该通知就是一个NOTIFY（消息）指示。也将被&#8220;声音所及&#8221;范围之内的所有计算机接受。计算机将 &#8220;感知&#8221;该设备已经向自己&#8220;报到&#8221;。实际上，NOTIFY（消息）指示也不是单单发送给计算机听的，别的网络设备也可以听到。</p>
<p>就是在上述的一播一听之间，出现了问题！</p>
<p>如果某个黑客向某个用户系统发送一个NOTIFY（消息）指示，该用户系统就会收到这个NOTIFY（消息）指示并在其指示下，连接到一个特定服务器上，接着向相应的服务器请求下载服务―――下载将要执行的服务内容。服务器当然会响应这个请求。UPnP服务系统将解释这个设备的描述部分，请求发送更多的文件，服务器又需要响应这些请求。这样，就构成一个&#8220;请求――响应&#8221;的循环，大量占用系统资源，造成UPnP系统服务速度变慢甚至停止。所以，这个缺陷将导致&#8220;拒绝服务&#8221;攻击称为可能！</p>
<p>结束语</p>
<p>UpnP正在向我们一步步走近，现在已经是足声可闻了。不久的将来，必然对我们的工作和生活产生巨大影响。也蕴含着无限商机。尽管现在存在问题，也难保以后就不会再出现新的问题，但这既然体现了人的需求意向，就会有巨大的生命力，暂时的挫折不会使得它停下前进的脚步！&nbsp; <br></p>
<img src ="http://www.cppblog.com/killsound/aggbug/39054.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2007-12-19 16:47 <a href="http://www.cppblog.com/killsound/archive/2007/12/19/39054.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Debug 运行正常但 Release 失败的问题,Debug 和 Release 编译方式的本质区别</title><link>http://www.cppblog.com/killsound/archive/2007/02/26/18997.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Mon, 26 Feb 2007 08:57:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2007/02/26/18997.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/18997.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2007/02/26/18997.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/18997.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/18997.html</trackback:ping><description><![CDATA[经常在 CSDN 上看见有人问 Debug 运行正常但 Release 失败的问题。以往的讨论往往是经验性的，并没有指出会这样的真正原因是什么，要想找出真正的原因通常要凭运气。最近我看了一些这方面的书，又参考了 CSDN 上的一些帖子，然后深入研究了一下关于二者的不同。以下是我的一些体会，拿来与大家共享。 -------------------------------------- 本文主要包含如下内容：<br /> 1. Debug 和 Release 编译方式的本质区别 <br />2. 哪些情况下 Release 版会出错 <br />2. 怎样"调试" Release 版的程序 -------------------------------------- <br />关于Debug和Release之本质区别的讨论 一、Debug 和 Release 编译方式的本质区别 Debug 通常称为调试版本，它包含调试信息，并且不作任何优化，便于程序员调试程序。Release 称为发布版本，它往往是进行了各种优化，使得程序在代码大小和运行速度上都是最优的，以便用户很好地使用。 Debug 和 Release 的真正秘密，在于一组编译选项。下面列出了分别针对二者的选项（当然除此之外还有其他一些，如/Fd /Fo，但区别并不重要，通常他们也不会引起 Release 版错误，在此不讨论） Debug 版本： /MDd /MLd 或 /MTd 使用 Debug runtime library(调试版本的运行时刻函数库) /Od 关闭优化开关 /D "_DEBUG" 相当于 #define _DEBUG,打开编译调试代码开关(主要针对 assert函数) /ZI 创建 Edit and continue(编辑继续)数据库，这样在调试过 程中如果修改了源代码不需重新编译 /GZ 可以帮助捕获内存错误 /Gm 打开最小化重链接开关，减少链接时间 Release 版本： /MD /ML 或 /MT 使用发布版本的运行时刻函数库 /O1 或 /O2 优化开关，使程序最小或最快 /D "NDEBUG" 关闭条件编译调试代码开关(即不编译assert函数) /GF 合并重复的字符串，并将字符串常量放到只读内存，防止 被修改 实际上，Debug 和 Release 并没有本质的界限，他们只是一组编译选项的集合，编译器只是按照预定的选项行动。事实上，我们甚至可以修改这些选项，从而得到优化过的调试版本或是带跟踪语句的发布版本。 二、哪些情况下 Release 版会出错 有了上面的介绍，我们再来逐个对照这些选项看看 Release 版错误是怎样产生的 1. Runtime Library：链接哪种运行时刻函数库通常只对程序的性能产生影响。调试版本的 Runtime Library 包含了调试信息，并采用了一些保护机制以帮助发现错误，因此性能不如发布版本。编译器提供的 Runtime Library 通常很稳定，不会造成 Release 版错误；倒是由于 Debug 的 Runtime Library 加强了对错误的检测，如堆内存分配，有时会出现 Debug 有错但 Release 正常的现象。应当指出的是，如果 Debug 有错，即使 Release 正常，程序肯定是有 Bug 的，只不过可能是 Release 版的某次运行没有表现出来而已。 2. 优化：这是造成错误的主要原因，因为关闭优化时源程序基本上是直接翻译的，而打开优化后编译器会作出一系列假设。这类错误主要有以下几种： (1) 帧指针(Frame Pointer)省略（简称 FPO ）：在函数调用过程中，所有调用信息（返回地址、参数）以及自动变量都是放在栈中的。若函数的声明与实现不同（参数、返回值、调用方式），就会产生错误————但 Debug 方式下，栈的访问通过 EBP 寄存器保存的地址实现，如果没有发生数组越界之类的错误（或是越界"不多"），函数通常能正常执行；Release 方式下，优化会省略 EBP 栈基址指针，这样通过一个全局指针访问栈就会造成返回地址错误是程序崩溃。C++ 的强类型特性能检查出大多数这样的错误，但如果用了强制类型转换，就不行了。你可以在 Release 版本中强制加入 /Oy- 编译选项来关掉帧指针省略，以确定是否此类错误。此类错误通常有：<br /><br /> ● MFC 消息响应函数书写错误。正确的应为 afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam); ON_MESSAGE 宏包含强制类型转换。防止这种错误的方法之一是重定义 ON_MESSAGE 宏，把下列代码加到 stdafx.h 中（在#include "afxwin.h"之后）,函数原形错误时编译会报错 #undef ON_MESSAGE #define ON_MESSAGE(message, memberFxn) \ { message, 0, 0, 0, AfxSig_lwl, \ (AFX_PMSG)(AFX_PMSGW)(static_cast&lt; LRESULT (AFX_MSG_CALL \ CWnd::*)(WPARAM, LPARAM) &gt; (&amp;memberFxn) }, (2) volatile 型变量：volatile 告诉编译器该变量可能被程序之外的未知方式修改（如系统、其他进程和线程）。优化程序为了使程序性能提高，常把一些变量放在寄存器中（类似于 register 关键字），而其他进程只能对该变量所在的内存进行修改，而寄存器中的值没变。如果你的程序是多线程的，或者你发现某个变量的值与预期的不符而你确信已正确的设置了，则很可能遇到这样的问题。这种错误有时会表现为程序在最快优化出错而最小优化正常。把你认为可疑的变量加上 volatile 试试。 (3) 变量优化：优化程序会根据变量的使用情况优化变量。例如，函数中有一个未被使用的变量，在 Debug 版中它有可能掩盖一个数组越界，而在 Release 版中，这个变量很可能被优化调，此时数组越界会破坏栈中有用的数据。当然，实际的情况会比这复杂得多。与此有关的错误有：<br /><br /> ● 非法访问，包括数组越界、指针错误等。 <br />例如 void fn(void) { int i; i = 1; int a[4]; { int j; j = 1; } a[-1] = 1;//当然错误不会这么明显，例如下标是变量 a[4] = 1; } j 虽然在数组越界时已出了作用域，但其空间并未收回，因而 i 和 j 就会掩盖越界。而 Release 版由于 i、j 并未其很大作用可能会被优化掉，从而使栈被破坏。 3. _DEBUG 与 NDEBUG ：当定义了 _DEBUG 时，assert() 函数会被编译，而 NDEBUG 时不被编译。除此之外，VC++中还有一系列断言宏。这包括： ANSI C 断言 void assert(int expression ); C Runtime Lib 断言 _ASSERT( booleanExpression ); _ASSERTE( booleanExpression ); MFC 断言 ASSERT( booleanExpression ); VERIFY( booleanExpression ); ASSERT_VALID( pObject ); ASSERT_KINDOF( classname, pobject ); ATL 断言 ATLASSERT( booleanExpression ); 此外，TRACE() 宏的编译也受 _DEBUG 控制。 所有这些断言都只在 Debug版中才被编译，而在 Release 版中被忽略。唯一的例外是 VERIFY() 。事实上，这些宏都是调用了 assert() 函数，只不过附加了一些与库有关的调试代码。如果你在这些宏中加入了任何程序代码，而不只是布尔表达式（例如赋值、能改变变量值的函数调用 等），那么 Release 版都不会执行这些操作，从而造成错误。初学者很容易犯这类错误，查找的方法也很简单，因为这些宏都已在上面列出，只要利用 VC++ 的 Find in Files 功能在工程所有文件中找到用这些宏的地方再一一检查即可。另外，有些高手可能还会加入 #ifdef _DEBUG 之类的条件编译，也要注意一下。 顺便值得一提的是 VERIFY() 宏，这个宏允许你将程序代码放在布尔表达式里。这个宏通常用来检查 Windows API 的返回值。有些人可能为这个原因而滥用 VERIFY() ，事实上这是危险的，因为 VERIFY() 违反了断言的思想，不能使程序代码和调试代码完全分离，最终可能会带来很多麻烦。因此，专家们建议尽量少用这个宏。 4. /GZ 选项：这个选项会做以下这些事 (1) 初始化内存和变量。包括用 0xCC 初始化所有自动变量，0xCD ( Cleared Data ) 初始化堆中分配的内存（即动态分配的内存，例如 new ），0xDD ( Dead Data ) 填充已被释放的堆内存（例如 delete ），0xFD( deFencde Data ) 初始化受保护的内存（debug 版在动态分配内存的前后加入保护内存以防止越界访问），其中括号中的词是微软建议的助记词。这样做的好处是这些值都很大，作为指针是不可能的（而且 32 位系统中指针很少是奇数值，在有些系统中奇数的指针会产生运行时错误），作为数值也很少遇到，而且这些值也很容易辨认，因此这很有利于在 Debug 版中发现 Release 版才会遇到的错误。要特别注意的是，很多人认为编译器会用 0 来初始化变量，这是错误的（而且这样很不利于查找错误）。 (2) 通过函数指针调用函数时，会通过检查栈指针验证函数调用的匹配性。（防止原形不匹配） (3) 函数返回前检查栈指针，确认未被修改。（防止越界访问和原形不匹配，与第二项合在一起可大致模拟帧指针省略 FPO ） 通常 /GZ 选项会造成 Debug 版出错而 Release 版正常的现象，因为 Release 版中未初始化的变量是随机的，这有可能使指针指向一个有效地址而掩盖了非法访问。 除此之外，/Gm /GF 等选项造成错误的情况比较少，而且他们的效果显而易见，比较容易发现。 三、怎样"调试" Release 版的程序 遇到 Debug 成功但 Release 失败，显然是一件很沮丧的事，而且往往无从下手。如果你看了以上的分析，结合错误的具体表现，很快找出了错误，固然很好。但如果一时找不出，以下给出了一些在这种情况下的策略。 1. 前面已经提过，Debug 和 Release 只是一组编译选项的差别，实际上并没有什么定义能区分二者。我们可以修改 Release 版的编译选项来缩小错误范围。如上所述，可以把 Release 的选项逐个 注：那篇文章到此就完了，好像还有一些没了。 <br /><br />在VC中当整个工程较大时，软件时常为出现在DEBUG状态下能运行而在RELEASE状态下无法运行的情况。由于开发者通常在DEBUG状态下开发软件，所以这种情况时常是在我们辛苦工作一两个月后，满怀信心的准备将软件发行时发生。为了避免无谓的损失，我们最好进行以下的检查: 1、时常测试软件的两种版本。 2、不要轻易将问题归结为DEBUG/RELEASE问题，除非你已经充分对两种版本进行了测试。 3、预处理的不同，也有可能引起这样的问题。出现问题的一种可能性是在不同版本的编译间定义了不同的预处理标记。请对你的DEBUG版本的软件试一下以下改动： 在"Project Setting(ALT-F7)" 中的C/C++项中设置目录(category)为"General"，并且改动"_DEBUG"定义为"NDEBUG". 设置目录为"Preprocessor"并且添加定义"_DEBUG到"Undefined Symbols"输入框. 选择Rebuild ALL,重新编译. 如果经过编译的程序产生了问题，请对代码进行如下改动： 将ASSERT() 改为 VERIFY(). 找出定义在"#ifdef _DEBUG"中的代码，如果在RELEASE版本中需要这些代码请将他们移到定义外。 查找TRACE(...)中代码，因为这些代码在RELEASE中也不被编译。 所以请认真检查那些在RELEASE中需要的代码是否并没有被便宜。 4、变量的初始化所带来的不同，在不同的系统，或是在DEBUG/RELEASE版本间都存在这样的差异，所以请对变量进行初始化。 5、是否在编译时已经有了警告?请将警告级别设置为3或4,然后保证在编译时没有警告出现. 6、是否改动了资源文件. 7、此外对RELEASE版本的软件也可以进行调试，请做如下改动： 在"Project Settings" 中 "C++/C " 项目下设置 "category" 为 "General" 并且将"Debug Info"设置为 "Program Database". 在"Link"项目下选中"Generate Debug Info"检查框。 "Rebuild All" 如此做法会产生的一些限制： 无法获得在MFC DLL中的变量的值。 必须对该软件所使用的所有DLL工程都进行改动。 另： MS BUG：MS的一份技术文档中表明，在VC5中对于DLL的"Maximize Speed"优化选项并未被完全支持，因此这将会引起内存错误并导致程序崩溃。 <img src ="http://www.cppblog.com/killsound/aggbug/18997.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2007-02-26 16:57 <a href="http://www.cppblog.com/killsound/archive/2007/02/26/18997.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一起讨论一个BSTR类型转换问题 </title><link>http://www.cppblog.com/killsound/archive/2007/02/26/18989.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Mon, 26 Feb 2007 06:20:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2007/02/26/18989.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/18989.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2007/02/26/18989.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/18989.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/18989.html</trackback:ping><description><![CDATA[
		<div class="postbody">
				<font color="#0099ff">1. 使用_bstr_t解决内存问题</font>
				<br />
				<br />    COM编程当中一个重要的主题就是维护 BSTR 类型变量. 在一些情况下(主要是传递或者复制 BSTR 类型数据的时候)会产生一些问题: <br />    * 函数不能接收 BSTR 类型的变量参数 <br />    * 复制 BSTR 类型数据的时候导致内存泄漏 <br /><br />    通常使用 _bstr_t 对象可以解决这些问题, 这个对象封装了 BSTR 数据类型, 自动进行资源的分配合管理, 并且提供一个自动的数据类型转换操作. <br /><br />    注意: 使用强制类型转换 _bstr_t 的方式对于 Unicode 模式链接是不适用的, 需要使用 Win32 模式链接.  <br /><br />    此外, 这里也有一个内存管理的问题, 使用赋值模式就会产生内存泄漏: <br />    BSTR tmpBStr; <br />    m_pObject1-&gt;get_ObjectString(&amp;tmpBStr); <br />    _bstr_t tmpbstr; <br />    tmpbstr= tmpBStr; //内存泄漏 <br />     SetDlgItemText(IDC_CURPROPVAL, tmpbstr); <br /><br />    在 tmpbstr 变量初始化的时候发生泄漏, 函数 SysAllocString 在创建 tmpbstr 变量的时候被自动调用. 这个新申请的资源以后不会释放, 导致内存泄漏.  <br /><br /> 2. BSTR 数据类型 <br /> 1) BSTR , LPWSTR 和 LPSTR <br />    LPSTR 就是我们日常使用的一个MFC的char*指针的宏定义, LPWSTR 比 LPSTR 多一倍的资源使用, 因为它和汉字一样使用双字节表达一个字符, BSTR 则额外多一个信息头部存放数据长度. <br /><br /> 2) 如何将LPSTR/LPCTSTR转换成为BSTR/LPWSTR <br />    其实MFC/ATL提供了一组宏定义用于转换这些数据类型, 因为需要先使用USES_CONVERSION;宏, 里面调用了_alloc申请并且自动释放需要的资源, 为此你不必担心前面提到的内存维护问题: <br />    A2BSTR    OLE2A    T2A    W2A  <br />    A2COLE    OLE2BSTR T2BSTR W2BSTR  <br />    A2CT      OLE2CA   T2CA   W2CA  <br />    A2CW      OLE2CT   T2COLE W2COLE  <br />    A2OLE     OLE2CW   T2CW   W2CT  <br />    A2T       OLE2T    T2OLE  W2OLE  <br />    A2W       OLE2W    T2W    W2T  <br /><br />    或者你可以使用MSDN里面的一个无法通过索引提到的两个函数实现字符串到BSTR的转换 <br /><br />    //使用 /Gr 或者 /Gz 编译开关, 或者包含一个 comsupp.lib 就行了 <br />    #include &lt;comutil.h&gt; <br />    int main() <br />    { <br />       char sz[]="hello"; <br />       _bstr_t b; <br />       b = _com_util::ConvertStringToBSTR(sz); <br />       char * p = _com_util::ConvertBSTRToString(b); <br />       return 1; <br />    }  <br /></div>
<img src ="http://www.cppblog.com/killsound/aggbug/18989.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2007-02-26 14:20 <a href="http://www.cppblog.com/killsound/archive/2007/02/26/18989.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编写INF文件进行文件安装(转载)</title><link>http://www.cppblog.com/killsound/archive/2007/01/25/17970.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Thu, 25 Jan 2007 01:08:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2007/01/25/17970.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/17970.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2007/01/25/17970.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/17970.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/17970.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 丁健												张万												江南																		安装信息				(Setup Information)				文件是				Windows				系统支持的一种安装信息存放文件，一般以				INF				作为扩展名，因此也叫				INF				文件。安装信息				INF...&nbsp;&nbsp;<a href='http://www.cppblog.com/killsound/archive/2007/01/25/17970.html'>阅读全文</a><img src ="http://www.cppblog.com/killsound/aggbug/17970.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2007-01-25 09:08 <a href="http://www.cppblog.com/killsound/archive/2007/01/25/17970.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>InstallShield内部库函数之5 Sd对话框函数</title><link>http://www.cppblog.com/killsound/archive/2007/01/18/17745.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Thu, 18 Jan 2007 03:58:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2007/01/18/17745.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/17745.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2007/01/18/17745.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/17745.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/17745.html</trackback:ping><description><![CDATA[
		<strong>
				<span id="dgfiList__ctl3_Title">[转载]InstallShield内部库函数之5 Sd对话框函数</span>
				<br />
		</strong>
		<span id="dgfiList__ctl3_Body">InstallShield内部库函数之5  Sd对话框函数<br />    InstallShield提供一些Sd对话框函数，用户可自定义和显示。Sd对话框使用可以创建用户输入的对话框的特殊脚本定义函数来创建。然后该对话框根据所作选择返回值给脚本。<br />    Sd对话框有一个Cancel按钮，当它被选中时不返回一个CANCEL值。而是调用缺省的退出处理。<br />下面是所有有效的Sd对话框函数的列表：<br />DialogSetInfo<br />改变由一些内部对话框函数呈现的对话框的显示元素。<br />SdAskDestPath<br />呈现一个对话框，允许最终用户指定安装的一个目标位置。<br />SdAskOptions<br />创建一个对话框，它比标准AskOptions函数更灵活。<br />SdAskOptionsList<br />呈现一个对话框，允许最终用户选定和撤消选定一个列表中的项目。<br />SdBitmap<br />在对话框中显示一个位图。<br />SdComponentDialog<br />显示一个对话框，允许最终用户选择安装的组件和目标文件夹。<br />SdComponentDialog2<br />显示一个对话框，允许最终用户选择要安装的文件夹、组件和子部件。<br />SdComponentDialogAdv<br />显示一个对话框，允许最终用户选择安装的组件和目标文件夹。<br />SdComponentMult<br />显示一个对话框，允许最终用户选择安装的组件和子部件。有关磁盘空间的附加信息也被提供来确定安装的最佳位置。<br />SdComponentTree<br />显示一个有树形控制控件的对话框，允许最终用户选择安装的组件和子部件。有关磁盘空间的附加信息也被提供来确定安装的最佳位置。<br />SdConfirmNewDir<br />提示用户确认文件夹的选择。<br />SdConfirmRegistration<br />提示最终用户确认输入到由SdRegisterUser或SdRegisterUserEx呈现对话框中的信息。<br />SdDisplayTopics<br />显示主题列表。<br />SdExceptions<br />显示一个对话框，通知最终用户遇到一个共享、锁定（在使用中）或只读文件。<br />SdFinish<br />显示一个对话框，通知最终用户安装完成并提供一个选项的选择，如是否要查看信息文件或运行一个应用程序。<br />SdFinishEx<br />显示一个对话框，通知最终用户安装完成。<br />SdFinishReboot<br />显示一个对话框，通知用户安装完成并提供一个重启Windows 和计算机选项的选择。<br />SdInit<br />准备一个调用Sd对话框函数的安装。<br />SdLicense<br />显示一个许可证协议并给最终用户一个接受或拒绝许可证条款的选项。<br />SdLoadString<br />返回和一个指定资源ID相联系的字符串值。<br />SdMakeName<br />创建一个自定义对话框的节名。该节名在向一个 .iss文件写或从一个.iss文件读时使用。.iss文件由 InstallShield Silent使用。<br />SdOptionsButtons<br />显示一个有用户定义按钮的对话框，提供给最终用户不同选择。<br />SdProductName<br />在脚本对话框的特定静态区中插入你的产品名。<br />SdRegisterUser<br />显示一个可输入用户名和公司名的对话框。<br />SdRegisterUserEx<br />显示一个对话框，最终用户可在里面输入用户姓名、公司名称和应用程序序列号。<br />SdSelectFolder<br />呈现一个对话框，允许最终用户从程序文件夹列表中选择一个文件夹。<br />SdSetupType<br />显示一个对话框，使最终用户能选择三种标准安装类型之一：典型、简易或自定义。<br />SdSetupTypeEx<br />显示一个对话框，允许最终用户选择标准或自定义安装类型。<br />SdShowAnyDialog<br />显示一个资源DLL的通用对话框。当用SdShowAnyDialog函数显示一个对话框时你不能从最终用户接受任何输入。<br />SdShowDlgEdit1<br />显示一个对话框，它有一个单行的编辑区和其它静态控件。<br />SdShowDlgEdit2<br />显示一个对话框，有两个单行的编辑区和其它静态控件。<br />SdShowDlgEdit3<br />显示一个对话框，有三个单行的编辑区和其它静态控件。<br />SdShowFileMods<br />呈现一个对话框，预览对文件的可能修改并允许最终用户同意修改、拒绝修改或要求将修改写到一个文件中。<br />SdShowInfoList<br />在一个对话框中显示一个可滚动的消息列表。<br />SdShowMsg<br />在一个小窗口中显示一个消息。<br />SdStartCopy<br />呈现一个对话框，显示已经由最终用户指定的选项和设置。<br />SdWelcome<br />显示一个通用欢迎。<br />SdWelcomeMaint<br />显示一个在维护安装开始时使用的对话框。<br />5.1  DialogSetInfo<br />语法：DialogSetInfo (nInfoType, szInfoString, nParameter);<br />说明：DialogSetInfo函数修改下列在InstallShield对话框中显示的元件：<br />显示的图象；<br />得到最终用户选择的复选框的风格；<br />指示有效和所需磁盘空间值的精度。<br />    通过调用DialogSetInfo产生的修改对安装的剩余部分保持为有效或直到它们又被随后的对DialogSetInfo的调用修改。如果你的脚本在调用任何Sd对话框函数前调用DialogSetInfo，在 DialogSetInfo的调用前必须先调用SdInit。否则，对DialogSetInfo的调用无效。<br />参数：<br />nInfoType<br />指定要修改的显示特征。在该参数位置传递下列预定义的常量之一：<br />DLG_INFO_USEDECIMAL：缺省时，显示的指示组件大小、有效磁盘空间和所需磁盘空间的值被四舍五入到最近的KB或MB。下列对话框受该参数影响：ComponentDialog, SdComponentDialog, SdComponentDialog2, SdComponentDialogAdv 和SdComponentMult。<br />DLG_INFO_KUNITS：缺省时，显示的指示组件大小、有效磁盘空间和所需磁盘空间的值以KB为度量。传递该参数同时nParameter设置为FALSE时则以MB为度量显示这些值。下列对话框受该参数影响：SdComponentTree, ComponentDialog, SdComponentDialog, SdComponentDialog2, SdComponentDialogAdv 和SdComponentMult。<br />DLG_INFO_ALTIMAGE：指定一个显示在该对话框中的候选位图。如果nParameter设置为TRUE，szInfoString必须指定在该对话框显示的图象。该参数应用于所有在对话框右上角显示标准安装图象的InstallShield对话框（和图象显示在对话框左边一个大图象的右上角的Welcome, SdWelcome和SdFinish对话框）。更多的信息可查看下面参数nParameter处描述的"当nInfoType是．DLG_INFO_ALTIMAGE"。<br />    由SetDisplayEffect设置的显示效果不能应用到交替图象,通常它们显示时没有任何特殊效果.<br />DLG_INFO_CHECKSELECTION：指定选择方法将由nParameter传递的常量确定。注意SdComponentTree不支持改变复选框类型。<br />szInfoString<br />当DLG_INFO_ALTIMAGE传递给nInfoType时，该参数指定要显示的候选位图的文件名和一组位图属性（可选）。如果包括了位图属性，传递给该参数的字符串必须如下格式化：<br /> "位图文件名；透明标志；&lt;未用&gt;；&lt;未用&gt;；透明色"<br />位图文件名：<br />指定位图文件名。如果文件名未限定（也就是说，如果它不包括一个驱动器指示符和路径），InstallShield在SUPPORTDIR查找该位图。<br />透明标志：<br />指示是否透明显示位图。当该标志是1（真）时，该位图中所有其颜色是由szInfoString的透明色参数指定的RGB值的部分都透明显示。该参数缺省为0（非透明）。<br />未用：<br />格式行的这些部分都被忽略，但它们必须被包括。也就是说，格式行串必须包括四个分号，三个分号在透明标志和透明色之间。<br />透明色：<br />指示透明显示的颜色。透明色必须用一个RGB值来表示，也就是，三个数值型值由逗号分隔。如果没有指定值，即使透明标志设置为1，位图也不会被透明显示。<br />    下面的例子将显示MyBitmap.bmp文件的位图，它位于SUPPORTDIR文件夹。位图所有黑色部分（RGB值为0，0，0）将被透明显示。<br />"MyBitmap.bmp;1;;;0,0,0"<br />注意：标准位图为57×53。一个候选位图必须也约是这个大小。如果位图大于这个大小，它会在标题区中垂直置中，位图的右边将和对话框的右边对齐。（在Welcome, SdWelcome, 和 SdFinish对话框中，位图的右边将和它所呈现在的更大的位图的右边对齐）。位图左边将尽可能扩展到对话框左边。位图扩展在对话框标题区下的任何部分将被剪切掉。如果位图小于57×53，它将被正确显示，但它将不被调整大小或被扩展。<br />    当缺省位图被重新装入或nInfoType不是DLG_INFO_ALTIMAGE时该参数被忽略<br />nParameter<br />和nInfoType相联系一起来指定对话框特性。<br />当nInfoType是DLG_INFO_CHECKSELECTION时，传递下列预定义常量之一来指定复选框风格：<br />CHECKBOX：指定Windows 3.1风格的复选框。<br />CHECKBOX95：指定标准（Windows 95 风格）复选框。如果不调用DialogSetInfo，这是缺省的复选框风格。<br />CHECKLINE：指定复选行风格的复选框。<br />CHECKMARK：指定复选标记风格的复选框。<br />当nInfoType是DLG_INFO_ALTIMAGE，传递下列预定义常量之一来指定显示位图：<br />-1：指定对话框必须显示缺省位图。<br />TRUE：指定由szInfoString指示的位图必须在随后的对话框中使用，就如前面在szInfoString下描述的一样。<br />当nInfoType是DLG_INFO_KUNITS 或DLG_INFO_USEDECIMAL时，传递下列预定义常量之一来指定大小如何显示：<br />TRUE：指定大小按照nInfoType指示的显示。<br />FALSE：指定大小按照缺省风格显示。<br />返回值：<br />0  表明函数成功设置了指定的风格。<br />&lt; 0  表明函数未能设置该风格。<br />注解：<br />·为预览调用DialogSetInfo的效果，运行InstallShield范例，改变对话框的属性（通过单击属性按钮），然后检验如SdComponentDialog2和 SdComponentMult的对话框的改变。<br />·每次你要改变一个对话框的细节方面时都必须调用DialogSetInfo。<br />你可以使用DLG_INFO_ALTIMAGE参数来激活16色、256色或真彩色（24位）的位图。注意当256色的位图在16色系统中显示或真彩色位图在256色系统中显示时会有颜色失真。建议你指定一与目标系统的颜色模式兼容的候选图象。<br />5.2  SdAskDestPath<br />语法：SdAskDestPath (szTitle, szMsg, svDir, nReserved);<br />说明：SdAskDestPath函数创建一个对话框，允许最终用户选择一个候选目标路径。当你单击对话框中的浏览按钮，SelectDir函数被调用来打开一个二次对话框使最终用户可以选择一个存在的文件夹或输入一个新的文件夹名。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择文件夹"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的文本。该文本被考虑为一个静态控件。在你的消息字符串中使用%P位置夹来插入已经由先前的一个对SdProductName的调用指定的产品名称（如果有）。为显示对话框的缺省指示，传递一个空字符串("")。<br />svDir<br />指定缺省选定的目录名。返回由最终用户选定的目录名。<br />nReserved<br />给该参数传递0。不允许其它值。<br />返回值：<br />NEXT (1)：指定Next按钮被单击。<br />BACK (12)：指定Back按钮被单击。<br />注解：<br />·运行在静止方式的安装程序必须创建在调用SdAskDestPath前不存在的新文件夹。这样可以确保确认对话框不被显示。没有这一步骤，则需要两个响应文件来处理两种可能情况。<br />5.3  SdAskOptions<br />语法：SdAskOptions (szTitle, szMsg1, szMsg2, szId, szComponents, nExclusiveFlag);<br />说明：SdAskOptions 函数创建一个对话框，提供安装选项。你可以使用复选框或单选钮作为选择按钮。显示在按钮旁边的信息从一组选项中检索得到。选项的缺省数目是4。必要时你可以增加或减去组中选项的数目。<br />    SdAskOptions运行于由系统变量MEDIA指定的当前媒体上。在安装的初始化中，InstallShield给MEDIA赋缺省媒体名（"DATA"），它和你的文件媒体库（Data1.cab）相联系。为显示脚本创建的组件，可按4.6中的相同步骤进行：<br />　　如果你的安装不使用一个安装类型的对话框，你必须在调用SdAskOptions之前调用ComponentSetupTypeSet来指定一个已经在IDE安装类型窗格中定义的安装类型<br />　　系统变量MEDIA的值在安装初始化过程中被设置为'DATA'。如果你改变该变量的值来指向一个脚本创建组件组，你必须在调用ComponentTransferData, CreateShellObjects, 或 CreateRegistrySet前将值修改回'DATA'。注意运行一个基于事件的脚本的安装中，ComponentTransferData被自动调用。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择组件"） ，给该参数传递一个空字符串（""）。<br />szMsg1<br />指定显示在对话框的消息。该静态区的ID是801。为显示该对话框的缺省指示，给该参数传递一个空字符串("")。<br />szMsg2<br />指定在对话框显示的一个二次消息。该静态区的ID是802。<br />SzId<br />指定一个候选数值型对话框ID。仅使用以字符串形式表示的数值型ID（例如，ID 13001 为"13001"）。你可以拷贝SdAskOptions对话框资源，对它做有限的修改，给它一个唯一数值型ID，并通过以字符串传递它的ID给szId来调用对话框。参考下面的注解部分。为创建标准的四选项的SdAskOptions对话框，给该参数传递一个空字符串("")。<br />szComponents<br />指定要显示的包含子部件的组件名称。子部件前面有复选框或单选钮。为显示所有顶层组件，给该参数传递一个空字符串（""）。<br />SdAskOptions在由系统变量MEDIA指定的文件媒体库或脚本创建组件组中查找所需组件。<br />nExclusiveFlag<br />指定你要在对话框中显示的按钮类型。在该参数位置传递下列预定义常量之一：<br />EXCLUSIVE：指定单选钮。<br />NONEXCLUSIVE：指定复选框。<br />　　如果你的安装包括必需的可见的组件，不要调用SdAskOptions来得到安装选项。而是，以非静止方式调用ComponentDialog, SdComponentDialog, SdComponentDialogAdv, SdComponentMult 或SdAskOptionsList。<br />　　必需组件可以这么理解：当活动组件（在组件窗格中被选择的组件）被安装时，你要添加组件到必须被安装的组件列表中或从该组件列表中删除组件。<br />其中控件有：<br />所需组件（列表框）：列出活动组件要求的组件。<br />组件（列表框）：列出所有定义的组件。活动组件有一个复选标记；所需组件有一个红圈和斜杠。<br />添加（按扭）：将在组件列表框中选定的组件添加到所需组件列表框中。<br />删除（按扭）：从所需列表框中删除选定的组件。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />·你可以通过使用资源编辑器拷贝SdAskOptions对话框资源（位于_isres.dll），对拷贝作有限的修改，并给它一个唯一ID来创建多个SdAskOptions类型的对话框。当你调用SdAskOptions并在参数szId传递对话框的自定义拷贝时，自定义拷贝被显示。限制对存在的静态文本区作编辑修改和增加静态文本区。不建议添加需要处理程序的控件，因为它需要改变SdAskOptions的资源脚本。<br />5.4  SdAskOptionsList<br />语法：SdAskOptionsList (szTitle, szMsg, szComponents, nStyle);<br />说明：SdAskOptionsList函数创建一个对话框，显示一个自定义安装的组件列表。<br />SdAskOptionsList运行在由系统变量MEDIA指定的当前媒体上。在安装的初始化中，InstallShield给MEDIA赋缺省媒体名（"DATA"），它和你的文件媒体库（Data1.cab）相联系。为显示脚本创建的组件，按4.6中的相同步骤进行。<br />系统变量MEDIA的值在安装初始化过程中被设置为'DATA'。如果你改变该变量的值来指向一个脚本创建组件组，你必须在调用ComponentTransferData, CreateShellObjects, 或 CreateRegistrySet前将值修改回'DATA'。注意运行一个基于事件的脚本的安装中，ComponentTransferData被自动调用。<br />　　如果你的安装不使用一个安装类型对话框，你必须在调用SdAskOptionsList前调用ComponentSetupTypeSet来指定一个已经在IDE安装类型窗格中定义的安装类型。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择组件"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定对话框中显示的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串（""）。<br />szComponents<br />指定要显示的包含子部件的组件名称。为显示所有顶层组件，给该参数传递一个空字符串。<br />SdAskOptionsList在由系统变量MEDIA指定的文件媒体库或脚本创建组件组中查找所需的组件。<br />nStyle<br />指定最终用户的选择是否受限。在该参数位置传递下列预定义常量之一：<br />EXCLUSIVE：允许最终用户仅从列表中选择一个项目。如果任何szComponents'的子部件是所需组件，则不使用EXCLUSIVE模式。<br />NONEXCLUSIVE：允许最终用户从列表中选择多个项目，包括多个非邻接的选项。两个按钮被显示：Select All 和Clear All,，允许通过单击一个按钮选择所有选项或清除所有选项。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />5.5  SdBitmap<br />语法：SdBitmap (szTitle, szMsg, szBitmap);<br />说明：SdBitmap函数在一个对话框中显示一个位图。位图所允许的最大大小是宽440个像素点、高275个像素点。仅当你使用一个资源编辑器来修改SdBitmap对话框资源使得显示消息的控件成为可见时，你才可以在SdBitmap对话框中显示一个消息，查看下面注解。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"欢迎"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />给该参数传递一个空字符串("")，除非你使用一个资源编辑器修改SdBitmap对话框来显示一个消息，查看下面注解。<br />szBitmap<br />指定要显示的位图的文件名和一组位图属性（可选）。如果包括位图属性，传递给该参数的字符串必须如下格式化：<br /> "位图文件名；透明标志'3-D标志；背景颜色"<br />位图文件名<br />指定位图文件名。如果文件名未限定（也就是说，如果它不包括一个驱动器指示符和路径），InstallShield在SUPPORTDIR查找该位图。<br />透明标志<br />指示是否透明显示位图。当该标志是1（真）时，该位图所有紫红色（RGB值：255，0，255）部分都透明显示。该参数的缺省值是0（非透明）。<br />3-D 标志<br />指示是否要绕着包含位图的静态区的边缘增加一个3-D边框。缺省为０（非３D边框）。<br />背景色<br />指示作为静态文本区背景的颜色。 注意该颜色仅当位图小于它所显示在的静态文本区或透明标志设置为1并且位图有透明区域时才会可见。背景色必须以RGB值表示，也就是三个由逗号分隔的数值型的值。<br />　　下面的例子将从MyBitmap.bmp文件显示位图，它位于SUPPORTDIR文件夹。该位图将被置于一个黑色背景上。它有一个3-D边框。该位图的任何紫红色的部分将被显示为背景色-黑色。<br />    "MyBitmap.bmp;1;1;0,0,0"<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />·你可以使用一个资源编辑器来修改SdBitmap对话框资源，使得一个传递给参数szMsg的消息字符串在SdBitmap对话框中显示。<br />·SdBitmap 对话框资源包括在_isres.dll中。该资源包含一个静态文本控件，它接收由参数szMsg传递的字符串。然而，该静态文本控件缺省为在SdBitmap对话框中不可查看（在对话框下）。SdBitmap也使用一个静态文本控件显示位图图象。你可以调整位图图象静态文本控件的大小和移动消息静态文本控件进入对话框来查看。<br />改变位图图象静态文本控制的大小可能影响你位图图象的显示。位图图象必须足够小来避免当它被SdBitmap在位图图象静态文本控制置中时被剪切掉。<br />·该函数不支持透明位图。如果你以该函数来使用一个透明位图，透明部分将被正常显示。<br />·SdBitmap不支持图元文件。<br />5.6  SdComponentDialog<br />语法：SdComponentDialog (szTitle, szMsg, svDir, szComponents);<br />说明：使用SdComponentDialog函数创建一个对话框。显示当前媒体上用户可以安装的的组件列表和每个组件将占用的磁盘空间。该函数和SdComponentDialogAdv相同。<br />    目标目录可以使用Browse按钮来修改；在其它驱动器上的可用磁盘空间可以使用Disk Space 按钮来检查。<br />SdComponentDialogt运行在由系统变量MEDIA指定的当前媒体上。在安装的初始化中，InstallShield给MEDIA赋缺省媒体名（"DATA"），它和你的文件媒体库（Data1.cab）相联系。为显示脚本创建的组件，按4.6中的相同步骤进行。<br />    如果你的安装不使用一个安装类型的对话框，你必须在调用SdComponentDialog之前调用ComponentSetupTypeSet来指定一个已经在IDE安装类型窗格中定义的安装类型。<br />    系统变量MEDIA的值在安装初始化过程中被设置为'DATA'。如果你改变该变量的值来指向一个脚本创建组件组，你必须在调用ComponentTransferData, CreateShellObjects, 或 CreateRegistrySet前将值修改回'DATA'。注意运行一个基于事件的脚本的安装中，ComponentTransferData被自动调用。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择组件"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定对话框中显示的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串（""）。<br />svDir<br />指定缺省选定的文件夹名；返回最终用户选择的文件夹名。注意由svDir指定的目标文件夹不会自动赋给TARGETDIR或其它任何系统变量。如果它要被使用，为将svDir值提供给安装，你必须将它赋给TARGETDIR或一个脚本定义的变量。<br />    我们建议用户给该参数传递TARGETDIR而不是一个字符串变量。如果你在该参数不传递TARGETDIR，当最终用户在一个不同驱动器选择一个目标时显示在对话框的所需磁盘空间不会被重算。<br />szComponents<br />指定其子部件要被显示的组件名称。为显示所有主组件，给该参数传递一个空字符串("")。<br />SdComponentDialog在由系统变量MEDIA指定的文件媒体库或脚本创建组件组中查找所需的组件。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />·一个组件在被选定前，其大小都显示为0。一旦它已经被选定，它的实际大小被显示。<br />·若有必要，组件名被截尾来允许显示最大可能的组件大小。显示大小的必要空间依赖于最大组件大小本身（2GB）、当前使用的组件大小选项、和用来在对话框显示组件信息的字体。组件大小选项由DialogSetInfo函数设置。<br />·一旦显示最大可能大小所需的空间被确定，若有必要，所有组件名均自动被截尾以适应剩余空间。这确保组件名不会覆盖组件大小。<br />·注意在这种方法下需要较少空间显示大小（或没有被选）的组件的名称仍然会被截尾。为了最大化执行并确保组件名完整显示，使组件名小于在组件对话中的有效空间。<br />·如果由svDir指定的缺省文件夹不存在于最终用户系统，除非最终用户按下Browse按钮并按下列步骤从选择文件夹对话框创建它，否则它不会被创建。因此，无论何时用户想在调用ComponentTransferData(必要时，它会创建文件夹)前指定一个要使用的缺省文件夹，为了确定该文件夹是否存在，当SdComponentDialog返回时都必须调用ExistDir 。如果不存在，调用CreatDir在最终用户系统上创建它。<br />·运行在静止方式(silent mode )的安装，如果在调用SdComponentDialog前文件夹不存在，必须创建该新文件夹。这样可以确保确认对话框不被显示。没有这一步，需要两个响应文件来处理两个可能情况。<br />·Disk Space按钮的ID是101。该按钮自动显示有效磁盘空间对话框。如果愿意你可以删除该按钮/选项。目录静态区需要一个ID为851。列表框ID有一个多选项风格。<br />5.7  SdComponentDialog2<br />语法：SdComponentDialog2 (szTitle, szMsg, szDir, szComponents);<br />说明：SdComponentDialog2函数创建一个对话框，显示一个用户可以安装的当前媒体上的组件列表。显示在组件窗口中的组件可以有子部件。如果一个组件有子部件，Change按钮将成为有效。单击Change按钮将生成选择子部件对话框，可以作进一步的选择。对每个组件和子部件，也提供说明。当用户选择或高亮显示组件时，其说明显示在对话框的说明区下。<br />    SdComponentDialog2运行在由系统变量MEDIA指定的当前媒体上。在安装的初始化中，InstallShield给MEDIA赋缺省媒体名（"DATA"），它和你的文件媒体库（Data1.cab）相联系。为显示脚本创建的组件，按4.6中的相同步骤进行。<br />    如果你的安装不使用一个安装类型的对话框，你必须在调用SdComponentDialog之前调用ComponentSetupTypeSet来指定一个已经在IDE安装类型窗格中定义的安装类型。<br />    系统变量MEDIA的值在安装初始化过程中被设置为'DATA'。如果你改变该变量的值来指向一个脚本创建组件组，你必须在调用ComponentTransferData, CreateShellObjects, 或 CreateRegistrySet前将值修改回'DATA'。注意运行一个基于事件的脚本的安装中，ComponentTransferData被自动调用。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择组件"） ，给该参数传递一个空字符串（""）<br />szMsg<br />指定对话框中显示的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串（""）。<br />szDir<br />指定目标目录的名称（目标位置）。注意由svDir指定的目标文件夹不会自动赋给TARGETDIR或其它任何系统变量。如果它要被使用，为将svDir值提供给安装，你必须将它赋给TARGETDIR或一个脚本定义的变量。<br />szComponents<br />指定其子部件要被显示的组件名称。为显示所有主组件，给该参数传递一个空字符串("")。<br />    SdComponentDialog2在由系统变量MEDIA指定的文件媒体库或脚本创建组件组中查找所需的组件。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />·一个组件在被选定前，其大小都显示为0。一旦它已经被选定，它的实际大小被显示。 <br />·若有必要，组件名称被截尾来允许显示最大可能的组件大小。显示大小的必要空间依赖于最大组件大小本身（2GB），当前使用的组件大小选项，和用来在对话框显示组件信息的字体。组件大小选项由DialogSetInfo函数设置。<br />·一旦显示最大可能大小所需的空间被确定，若有必要，所有组件名均自动被截尾以适应剩余空间。这确保组件名不会覆盖组件大小。<br />·注意在这种方法下需要较少空间显示大小（或没有被选）的组件的名称仍然会被截尾。为了最大化执行并确保组件名完整显示，使组件名小于在组件对话框中的有效空间。<br />·当且仅当被选定的组件有任何子部件时Change按钮才为有效。否则，它将变灰。<br />·如果一个组件被撤消选定，它的子部件也必须缺省为撤消选定。同样的，如果一个组件的所有子部件缺省为撤消选定，则父组件也必须缺省为撤消选定。有关组件和子部件的缺省选定设置请参考ComponentAddItem函数。<br />·当用户选定一个显示在对话框中的组件或子部件时，缺省选定设置被清除。如果用户撤消选定一个组件，所有它的子部件也将被撤消选定。如果用户撤消选定一个组件的所有子部件，该组件也将被撤消选定。<br />5.8  SdComponentDialogAdv<br />语法：SdComponentDialogAdv (szTitle, szMsg, svDir, szComponents);<br />说明：使用SdComponentDialogAdv函数创建一个对话框。显示当前媒体上用户可以安装的组件列表和每个组件将占用的磁盘空间。该函数和SdComponentDialog相同。<br />    目标目录可以使用Browse按钮来修改：同时在其它驱动器上的可用磁盘空间可以使用Disk Space 按钮来检查。<br />SdComponentDialogtAdv运行在由系统变量MEDIA指定的当前媒体上。在安装的初始化中，InstallShield给MEDIA赋缺省媒体名（"DATA"），它和你的文件媒体库（Data1.cab）相联系。为显示脚本创建的组件，按4.6中的相同步骤进行。<br />　　如果你的安装不使用一个安装类型的对话框，你必须在调用SdComponentDialog之前调用ComponentSetupTypeSet来指定一个已经在IDE安装类型窗格中定义的安装类型。<br />    系统变量MEDIA的值在安装初始化过程中被设置为'DATA'。如果你改变该变量的值来指向一个脚本创建组件组，你必须在调用ComponentTransferData, CreateShellObjects, 或 CreateRegistrySet.前将值修改回'DATA'。注意运行一个基于事件的脚本的安装中，ComponentTransferData被自动调用。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择组件"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定对话框中显示的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串（""）。<br />svDir<br />指定缺省选定的文件夹名；返回最终用户选择的文件夹名。注意由svDir指定的目标文件夹不会自动赋给TARGETDIR或其它任何系统变量。如果它要被使用，为将svDir值提供给安装，你必须将它赋给TARGETDIR或一个脚本定义的变量。<br />    我们建议用户给该参数传递TARGETDIR而不是一个字符串变量。如果你在该参数不传递TARGETDIR，当最终用户在一个不同驱动器选择一个目标时显示在对话框的所需磁盘空间不会被重算。<br />szComponents<br />指定其子部件要被显示的组件名称。为显示所有主组件，给该参数传递一个空字符串("")。<br />SdComponentDialogAdv在由系统变量MEDIA指定的文件媒体库或脚本创建组件组中查找所需的组件。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />请参阅5.7。<br />5.9  SdComponentMult<br />语法：SdComponentMult (szTitle, szMsg, szTargetDir, szComponents);<br />说明：SdComponentMult函数创建一个对话框，提供给最终用户一个选项来从当前媒体上的一个组件和子部件列表中选择。对话框有两个子窗口。如果被选定的组件有子部件，它们在第二个窗口中显示。对话框也显示所需的磁盘空间（依赖于被选定的组件和子部件）和目标目录的空闲磁盘空间来在安装过程中提供帮助。组件和/或子部件的说明可以通过单击它的名称在说明区中查看。<br />有关组件和子部件的详细情况请参阅7.1。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择组件"） ，给该参数传递一个空字符串（""）<br />szMsg<br />指定对话框中显示的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串（""）。<br />szTargetDir<br />指定将应用程序安装到的目标文件夹名。注意由svTargetDir指定的目标文件夹不会自动赋给TARGETDIR或其它任何系统变量。如果它要被使用，为将svTargetDir值提供给安装，你必须将它赋给TARGETDIR或一个脚本定义的变量。<br />szComponents<br />指定其子部件要被显示的组件名称。为显示所有主组件，给该参数传递一个空字符串("")。<br />SdComponentMult在由系统变量MEDIA指定的文件媒体库或脚本创建组件组中查找所需的组件。<br />    太长不能适应选择窗口的组件名将被从右截尾以适应有效空间。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />请参阅5.7。<br />5.10  SdComponentTree<br />语法：SdComponentTree (szTitle, szMsg, szDir, szComponents, nLevel);<br />说明：SdComponentTree函数显示一个对话框，它包含下列内容：<br />一个树形控件，最终用户可以在其中选定在他们系统上需要的组件和不选定在他们系统上不需要的组件。<br />选定组件的说明（组件属性说明文本）。<br />需要用来执行树形控件中指定的文件操作的磁盘空间，和由szDir指定路径的磁盘的有效空间。（所需磁盘空间的计算考虑在szDir指定的磁盘的簇的大小。）<br />SdComponentTree运行在由系统变量MEDIA指定的当前媒体上。在安装的初始化中，InstallShield给MEDIA赋缺省媒体名（"DATA"），它和你的文件媒体库（Data1.cab）相联系。为显示脚本创建的组件，按4.6中的相同步骤进行。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择组件"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定对话框中显示的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串（""）。szDir<br />指定在计算所需和有效磁盘空间中用到的磁盘的路径。<br />szComponents<br />指定其子部件要被显示的组件名称。为显示所有主组件，给该参数传递一个空字符串("")。<br />nLevel<br />指定当对话框第一次被显示时在树形控件中打开多少层组件和子部件。（例如，nLevel为2，则对话框首次显示时，第三和更低层的子部件在树形控件中被关闭。）<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />5.11  SdConfirmNewDir<br />语法：SdConfirmNewDir (szTitle, szDir, nReserved);<br />说明：SdConfirmNewDie函数创建一个对话框，显示一个文件夹名和一个确认的提示。如果最终用户单击Yes按钮，则一个新文件夹自动由该函数创建。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"确认新文件夹"） ，给该参数传递一个空字符串（""）。<br />szDir<br />指定要确认的目录名称。（通过调用SdAskDestPath来得到该信息）<br />nReserved<br />给该参数传递0。不允许其它值。<br />返回值：<br />YES (1)：表明单击了Yes按钮并且目录已经被确认并将被创建。<br />NO (0)：表明单击了No按钮，并且指定的目录不会被创建。<br />&lt;0：表明Yes被选定了但函数未能创建新目录。<br />5.12  SdConfirmRegistration<br />语法：SdConfirmRegistration (szTitle, szName, szCompany, szSerial, nReserved);<br />说明：SdConfirmRegistration函数创建一个对话框，显示用户名、公司名称和序列号。如果在该对话框的任何区域输入一个空字符串（""），显示的区域将为空。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"注册认可"） ，给该参数传递一个空字符串（""）。<br />szName<br />指定最终用户姓名。<br />szCompany<br />指定公司名称。<br />szSerial<br />指定序列号。如果该参数包含一个空字符串（""），序列号区不在对话框显示。<br />nReserved<br />给该参数传递0。不允许其它值。<br />返回值：<br />YES (1)：表明单击Yes按钮。<br />NO (0)：表明单击No按钮。<br />注解：<br />·为得到序列号和最终用户的姓名和公司名，调用SdRegisterUserEx。只要得到姓名和公司名，调用SdRegisterUser。<br />5.13  SdDisplayTopics<br />语法：SdDisplayTopics (szTitle, szMsg, listTopics, listDetails, nReserved);<br />说明：SdDisplayTopics 函数创建一个对话框，显示基于主题数据（资料）的信息。对话框提供一个标题然后是标题的主题和说明。你可以修改说明文本的字体风格以让它和标题（主题）文本想区别。消息和主题标题通常是粗体。可使用该对话框显示帮助主题、例子等。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"自定义安装帮助"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定对话框中显示的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串（""）。<br />listTopics<br />指定要显示的包含主题的字符串列表。<br />listDetails<br />指定包含每个主题的说明的字符串列表。<br />nReserved<br />给该参数传递0。不允许其它值。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />·消息静态区必须以801为ID。主题标识符ID必须在802-849的范围之内。说明区ID必须在851-899的范围之内。<br />·静态说明区的空间由对话框的大小固定。你不能动态改变listDetails列表的空间。如果主题和说明的数目小于静态区的数目，在空白区不显示任何内容，但对话框大小不会改变。<br />5.14  SdExceptions<br />语法：SdExceptions (nExceptionType, szFilename);<br />说明：SdExceptions函数显示一个对话框，通知最终用户遇到一个共享，锁定（在使用中）或只读的文件并提供适当的选项。<br />参数：<br />nExceptionType<br />指定遇到文件问题的类型。在该参数位置传递下列预定义常量之一：<br />SHARED：一个共享的文件，其引用计数器已经减为0。<br />READONLY：遇到一个只读文件。<br />LOCKED：遇到一个锁定文件。<br />szFilename<br />指定遇到问题的文件名。<br />返回值：<br />ERR_RETRY (4)：表明选定了Retry按钮。<br />ERR_IGNORE (5)：表明选定了Ignore按钮。<br />ERR_YES (6)：表明选定了Yes按钮。<br />ERR_NO (7)：表明选定了No按钮。<br />ERR_PERFORM_AFTER_REBOOT (100)：表明选定了Reboot按钮。<br />&lt;0：表明对话框不能被显示。<br />5.15  SdFinish<br />语法：SdFinish (szTitle, szMsg1, szMsg2, szOpt1, szOpt2, bvOpt1, bvOpt2);<br />说明：SdFinish函数显示一个对话框，通知最终用户安装已完成并给用户信息或选择。SdFinish对话框显示两个消息和两个复选框选择选项。例如，你可能想要提供给用户查看README文件或运行应用程序的选择。<br />    为在消息中或复选框说明中插入产品名称，在szMsg1, szMsg2, szOpt1, 和szOpt2传递的字符串中使用位置夹%P。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"安装完成"） ，给该参数传递一个空字符串（""）。<br />szMsg1<br />指定在对话框顶端显示的消息。为显示通知用户安装完成的缺省指示，给该参数传递一个空字符串（""）。<br />szMsg2<br />指定在对话框底部显示的消息。为显示缺省指示（"单击Finish按钮完成安装"），给该参数传递一个空字符串（""）。<br />szOpt1<br />指定显示在第一个复选框旁边的文本。给该参数传递一个空字符串("")来隐藏复选框。<br />szOpt2<br />指定显示在第二个复选框旁边的文本。给该参数传递一个空字符串("")来隐藏复选框。<br />bvOpt1<br />返回第一个复选框的选择状态（TRUE或FALSE）。<br />bvOpt2<br />返回第二个复选框的选择状态（TRUE或FALSE）。<br />返回值：<br />NEXT (1)：表明单击了Finish按钮。<br />注解：<br />·SdFinish没有选项来终止安装和重启最终用户的计算机。当SdFinish返回时，安装继续执行。当有必要提供给用户重启的选项时，可用调用SdFinishReboot来代替。<br />·因为SdFinish被设计为宣告安装结束，所以Back按钮被禁用。<br />5.16  SdFinishEx<br />语法：SdFinishEx (szTitle, szMsg1, szMsg2, szOpt1, szOpt2, bvOpt1, bvOpt2);<br />说明：SdFinishEx函数调用SdFinish或SdFinishReboot来显示一个对话框，通知最终用户安装已完成并给用户信息或选择。如果系统变量BATCH_INSTALL等于FALSE（表明安装过程中没有遇到锁定文件），SdFinishEx调用SdFinish来显示对话框。如果BATCH_INSTALL等于TRUE，SdFinishEx调用SdFinishReboot来显示对话框。<br />    为在消息中或复选框说明中插入产品名称，在szMsg1, szMsg2, szOpt1, 和szOpt2传递的字符串中使用位置夹%P。<br />参数：<br />参数和SdFinish的相同。如果BATCH_INSTALL等于TRUE，这些参数被忽略并调用 SdFinishReboot("","",SYS_BOOTMACHINE,"",0)。<br />返回值：<br />0：表明调用了SdFinish。<br />NEXT (1)：表明调用SdFinishReboot并且最终用户不重启计算机。<br />&lt;0：表明调用SdFinishReboot并且最终用户选择重启计算机，但重启失败。<br />5.17  SdFinishReboot<br />语法：SdFinishReboot (szTitle, szMsg1, nDefOption, szMsg2, nReserved);<br />说明：SdFinishReboot函数在你的安装结尾宣告安装完成并提供给用户重启系统的选项。重启系统允许修改Autoexec.bat,Config.sys和一些.ini文件使其起作用。<br />    SdFinishReboot对话框在静态文本区中显示两个消息。用参数szMsg1和szMsg2来设置这些区域的值。为在消息中或复选框说明中插入产品名称，在szMsg1和szMsg2传递的字符串中使用位置夹%P。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"安装完成"） ，给该参数传递一个空字符串（""）。<br />szMsg1<br />指定在对话框顶端显示的消息。为显示通知用户安装完成的缺省指示，给该参数传递一个空字符串（""）。<br />nDefOption<br />指定一个缺省单选按钮选项选择。在该参数位置传递下列预定义常量之一：<br />SYS_BOOTMACHINE：安装结束时重启计算机。<br />0：不重启计算机。.<br />szMsg2<br />指定显示在对话框底部的文本，提供用户要做什么的信息。为显示缺省指示，传递一个空字符串（""）。<br />nReserved<br />给该参数传递0。不允许其它值。<br />返回值：<br />WILL_REBOOT：表明用户选择重启系统。<br />NEXT (1)：表明用户没有选择重启系统或Windows。<br />&lt;0：表明用户选择重启系统或Windows，但重启失败。<br />注解：<br />·因为当其它InstallShield实例运行时，InstallShield将尽力不重启计算机，所以你必须在允许SdFinishReboot重启Windows或系统前关闭所有其它InstallShield实例。另外，你给用户的消息必须要求他们以后若要重启系统，则他们必须确保首先关闭所有其它的应用程序。<br />·InstallShield自动确保锁定的.dll和.exe文件在下一次系统启动时将被更新。<br />·因为SdFinishReboot被设计为宣告安装结束，所以Back按钮被禁用。<br />5.18  SdInit<br />语法：SdInit ( );<br />说明：SdInit函数准备一个调用Sd对话框函数的安装：装入所需的资源字符串，还原最小化的InstallShield窗口，并指定在Sd对话框中Windows 95风格的复选框。<br />参数：<br />该函数没有参数。<br />返回值：<br />0：表明安装为调用Sd对话框函数作好初始化。<br />1：表明为调用Sd对话框函数，安装已经被初始化。<br />注解：<br />·该函数由每个Sd函数自动调用。没有必要显式调用SdInit，除非你的脚本在调用任何Sd对话框函数前调用了DialogSetInfo。这种情况下，你的脚本必须在调用DialogSetInfo前调用SdInit；否则对DialogSetInfo的调用不起任何作用。<br />5.19  SdLicense<br />语法：SdLicense (szTitle, szMsg, szQuestion, szLicenseFile);<br />说明：SdLicense函数显示一个对话框，包含一个在多行编辑区的许可证协议。许可证协议保存在一个由参数szLicenseFile指定的文本文件中。<br />    用户可以上下滚动来阅读协议，然后必须选择Yes、No或Enable、Back按钮。因为这可能是你将显示的第一个对话框，你可能要禁止Back按钮。如果用户选择了Yes，安装将继续。如果用户选择了No,InstallShield将显示退出安装对话框。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"软件许可证协议"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在多行编辑区上方的静态文本区中的消息。为显示缺省指示，传递一个空字符串。<br />szQuestion<br />指定显示在多行编辑区下方的静态文本区中的文本。你可能在这儿放置一个问题，用户必须选择Yes 或 No来响应它。为显示缺省指示，给该参数传递一个空字符串("")。<br />szLicenseFile<br />指定包含许可证协议的文本文件名。该文件必须被加到安装文件窗格中适当语言文件夹中。<br />返回值：<br />YES (1)：表明用户选择了Yes按钮。<br />BACK (12)：表明用户选择了Back按钮。<br />注解：<br />·该函数不能返回NO，因为，如果用户选择了No按钮，将显示退出安装对话框。<br />·你也可以通过输入全限定名，在引号中，或一个Universal Naming Convention (UNC)路径来指定szLicenseFile。<br />·在szLicenseFile中的文本在超过1024个字符的一行后必须包含硬回车。该文件的文本必须以1024字节为间隔读入字符串列表。如果从szLicenseFile的文本不包含硬回车，单词会在SdLicense对话框中意外地回绕。<br />5.20  SdLoadString<br />语法：SdLoadString (nID);<br />说明：SdLoadString函数返回与指定的资源ID相联系的字符串值。安装引擎首先在_isuser.dll（如果该文件存在）中查找资源；如果资源没有找到，安装引擎在_isres.all中查找。<br />参数：<br />nID<br />指定一个在_isuser.dll或 _isres.dll中的字符串资源的标识符。一些nID的有效值可以在InstallShield  Professional  文件夹的 Script\Ifx\Include 的子文件夹的 Ifx.h文件中找到。<br />返回值：<br />非空字符串值<br />SdLoadString成功检索到字符串值。<br />空字符串值("")<br />表明SdLoadString失败。<br />5.21  SdMakeName<br />语法：SdMakeName (svSection, szDlg, szUnused, nvDlgName);<br />说明：SdMakeName函数为一个自定义对话框创建一个节名。该节名在写到一个.iss文件或从中读出时被使用，由InstallShiled Silent使用。<br />参数：<br />svSection<br />指定节名（InstallShield使用变量szDlg和 nvDlgName来给该变量置一个值）。该值由SilentReadData和 SilentWriteData.使用。<br />szDlg<br />指定自定义对话框的名称。<br />szUnused<br />该参数不使用，给它传递一个空字符串("")。<br />nvDlgName<br />指定记录SdMakeName被由szDlg命名的对话框调用的次数的计数器。InstallShield自动增加该计数器。为每个自定义对话框使用一个唯一的变量名。（可参阅下面的注解）<br />返回值：  无。<br />注解：<br />·为使节被适当命名，你必须在每个不同的自定义对话框的第四个参数使用一个唯一的变量名。做到这一点的简单方法是在szDlg使用对话框名来命名该变量。例如，当szDlg是"MyDlgOne",命名在第四个参数的变量为nvMyDlgOne；当szDlg是"MyDlgTwo"，命名该变量为nvMyDlgTwo。<br />5.22  SdOptionsButtons<br />语法：SdOptionsButtons (szTitle, szMsg, listButtons, listDescription);<br />说明：SdOptionsButtons函数显示一个对话框，包含一到四个位图按钮和一个简短的对每个按钮的文本说明。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择组件"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。为显示该对话框缺省指示（"请选择你要安装的组件"），给该参数传递一个空字符串（""）。<br />listButtons<br />指定一个包含一到四个元素的字符串列表。每个元素是一个格式化的指定显示在按钮上的位图的字符串。一个按钮将被用来显示列表中的每个字符串元素。字符串列表元素必须有下列格式：<br /> "@&lt;位图ID&gt;;&lt;位图图标标志&gt;;&lt;透明颜色&gt;"<br />由@符号开始字符串并后随位图ID。&lt;位图图标标志&gt;域是1（真）或0（假），表明位图被显示时在&lt;透明颜色&gt;域指定的颜色是否要透明显示。&lt;透明颜色&gt;域指定一个RGB值，它是位图的透明颜色。注意分号将ID和图标标志、图标标志和透明颜色分隔。<br />更多的信息可参阅下面的注解部分。<br />listDescription<br />指定一个包含一到四个字符串元素的字符串列表，每个相对应于参数listButtons中的一个字符串。每个字符串是一个和它相应按钮一起显示的文本说明。<br />返回值：<br />NEXT (1)：表明单击了NEXT按钮。<br />BACK (12)：表明单击了Back按钮。<br />101：对应于listButtons中的第一个字符串元素的按钮被选定。<br />102：对应于listButtons中的第二个字符串元素的按钮被选定。<br />103：对应于listButtons中的第三个字符串元素的按钮被选定。<br />104：对应于listButtons中的第四个字符串元素的按钮被选定。<br />注解：<br />·虽然SdOptionsButtons可以被使用为一个安装类型对话框，但还是推荐使用SdSetupTypeEx对话框来允许最终用户选择一个安装类型，因为它不需要任何用户化。注意如果你调用SdOptionsButtons来得到最终用户的安装类型选择，你必须然后调用ComponentButtons来为你的安装建立选择的安装类型。<br />·InstallShield提供可以被该函数调用的四个_isres.dll中的缺省位图。这些位图有从12001到12004的ID和在脚本范例中相应的典型、可移植、简易和自定义安装类型。<br />·如果你使用该对话框作其它用途或你想要使用_isres.dll中提供的类型之外的安装类型，你必须将你自己的自定义按钮加入到_isuser.dll对话框模板中并且然后在你的安装中包含自定义的_isuser.dll。<br />·为防止用户没有单击一个特定按钮时就退出对话框，在你调用SdOptionsButtons前调用Disable函数来禁止Next按钮。<br />5.23  SdProductName<br />语法：SdProductName (szProductName);<br />说明：SdProductName函数使得你的产品名对所有的%P位置夹都有效。%P位置夹在一些Sd对话框中的静态文本区中找到。另外，一些Sd对话框函数，如SdFinish，允许你在作为函数参数的字符串中包含%P。<br />参数：<br />szProductName<br />指定被安装的产品名。该名称将取代在Sd对话框的适当静态区出现的任何产品名位置夹（%P）。<br />返回值：<br />该函数没有返回值。<br />5.24  SdRegisterUser<br />语法：SdRegisterUser (szTitle, szMsg, svName, svCompany);<br />说明：SdRegisterUser函数创建一个对话框，检索用户姓名和公司名称。如果svName和svCompany都包含空字符串，InstallShield将从注册表中得到用户姓名和公司名称。<br />    仅当两个编辑区都存在数据时Next按钮才被激活。如果InstallShield可以从系统查找缺省姓名和公司名称，Next按钮被自动激活。完成时，SdRegisteruser调用RegDBSetDefaultRoot来将注册表开关键设置给HKEY_CLASSES_ROOT。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"用户信息"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。该文本被看作为一个静态控制。为显示该对话框缺省指示，给该参数传递一个空字符串（""）。<br />svName<br />返回由用户输入的姓名。注意SdRegisterUser显示该参数的初始值由用户进行编辑。如果svName和svCompany都是空字符串，在目标系统注册表中被找到的用户姓名将被显示来进行编辑。<br />svCompany<br />返回由用户输入的公司名称。注意SdRegisterUser显示该参数的初始值由用户进行编辑。如果svName和svCompany都是空字符串，在目标系统注册表中被找到的公司名称将被显示来进行编辑。<br />返回值：<br />NEXT (1)：表明单击了NEXT按钮。<br />BACK (12)：表明单击了Back按钮。<br />5.25  SdRegisterUserEx<br />语法：SdRegisterUserEx (szTitle, szMsg, svName, svCompany, svSerial);<br />说明：SdRegisterUserEx函数创建一个对话框，检索用户姓名、公司名称和序列号。如果svName和svCompany都包含空字符串，InstallShield将从注册表得到用户姓名和公司名称。<br />    仅当三个编辑区都存在数据时Next按钮才被激活。你不能让任何区域空白。<br />完成时，SdRegisteruser调用RegDBSetDefaultRoot来将注册表开关键设置给HKEY_CLASSES_ROOT。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"用户信息"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。该文本被看作为一个静态控件。为显示该对话框缺省指示，给该参数传递一个空字符串（""）。<br />svName<br />返回由用户输入的姓名。注意SdRegisterUserEx显示该参数的初始值由用户进行编辑。如果svName和svCompany都是空字符串，在目标系统注册表中被找到的用户姓名将被显示来进行编辑。<br />svCompany<br />返回由用户输入的公司名称。注意SdRegisterUserEx显示该参数的初始值由用户进行编辑。如果svName和svCompany都是空字符串，在目标系统注册表中被找到的公司名称将被显示来进行编辑。<br />svSerial<br />返回用户输入的序列号。你可以使用该信息并把它写入一个文件或者把它显示在一个确认对话框中。<br />返回值：<br />NEXT (1)：表明单击了NEXT按钮。<br />BACK (12)：表明单击了Back按钮。<br />5.26  SdSelectFolder<br />语法：SdSelectFolder (szTitle, szMsg, svDefGroup);<br />说明：SdSelectFolder函数显示供选择的程序文件夹。SdSelectFolder允许你提供一个缺省选择。用户也可以输入一个新的文件夹名。SdSelectFolder将仅返回被选择的或输入的文件夹名。它不能创建文件夹。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"选择程序文件夹"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。该文本被看作为一个静态控件。为显示该对话框缺省指示，给该参数传递一个空字符串（""）。<br />svDefGroup<br />返回被选文件夹的名称。<br />返回值：<br />NEXT (1)：表明单击了NEXT按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />·运行在Windows NT下的一个安装中，如果在调用SdSelectFolder前调用ProgDefGroup，由SdSelectFolder显示的程序文件夹（公用或专用）将依赖于传递给ProgDefGroupType的参数。<br />5.27  SdSetupType<br />语法：SdSetupType (szTitle, szMsg, svDir, nReserved);<br />说明：SdSetupType函数显示一个对话框允许最终用户选择三种标准安装类型之一：典型、简易或自定义。这些安装选项显示时有标准描述文本。如果你想加入其它安装类型或改变显示的安装类型名或描述，调用SdSetupTypeEx来替代。<br />    对话框也显示一个缺省的目标路径。一个Browse按钮装入一个对话框，允许最终用户通过输入一个新文件夹名或从一个列表中选择存在的文件夹来修改目标路径。如果最终用户输入一个不存在的文件夹名，将显示一个消息框来询问是否要创建该文件夹。如果最终用户单击Yes，该函数自动创建指定文件夹。指定文件夹的全限定路径在svDir返回。<br />如果最终用户在使用组件对话框来选定和撤消选定与已选安装类型相联系的组件后，返回到安装类型对话框，那么那些选择将丢失。这种情况发生是因为SdSetupType函数每次被调用时自动根据选中的安装类型复位缺省组件选项。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"安装类型"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。该文本被看作为一个静态控件。为显示该对话框缺省指示，给该参数传递一个空字符串（""）。<br />svDir<br />指定一个缺省文件夹名。返回最终用户所选的文件夹名。<br />nReserved<br />保留为将来使用。给该参数传递0。<br />返回值：<br />TYPICAL (301)：表明用户选择典型安装。<br />COMPACT (302)：表明用户选择简易安装。<br />CUSTOM (303)：表明用户选择自定义安装。<br />BACK (12)：表明单击Back按钮。<br />5.28  SdSetupTypeEx<br />语法：SdSetupTypeEx (szTitle, szMsg, szReserved, svSetupType, nReserved);<br />说明：SdSetupTypeEx函数显示一个对话框，当你指定除典型、简易和自定义之外的安装类型时，允许最终用户选择安装类型。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"安装类型"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。为显示该对话框缺省指示，给该参数传递一个空字符串（""）。<br />szReserved<br />给该参数传递一个空字符串("")。不允许其它值。<br />svSetupType<br />指定一个缺省安装类型和返回由最终用户选择的安装类型。为使在列表中的第一次安装为缺省选择，给该参数传递一个空字符串("")。在该参数返回的字符串将和在IDE中指定的安装类型名相匹配。<br />nReserved<br />给该参数传递0。不允许其它值。<br />返回值：<br />0：表明SdSetupTypeEx成功。<br />BACK (12)：表明单击了Back按钮。<br />5.29  SdShowAnyDialog<br />语法：SdShowAnyDialog (szTitle, szID, nID, nReserved);<br />说明：SdShowAnyDialog函数显示一个自定义或改进型对话框。该函数仅推荐给高级用户使用。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"欢迎"） ，给该参数传递一个空字符串（""）。<br />szID<br />指定标识对话框的标识符字符串。如果该参数包含一个空字符串("")，SdShowAnyDialog使用nID的值。<br />nID<br />指定标识对话框的数值型值。如果szID包含一个空字符串("")，该参数被忽略。<br />nReserved<br />给该参数传递0。不允许其它值。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />·为了使用SdShowAnyDialog函数，你必须知道你希望显示的_isres.dll中的改进型对话框或_isuser.dll中的自定义对话框的ID。<br />·如果对话框只有静态控件，你不需要修改SdShowAnyDialog脚本文件。但如果你的对话框有其它控件，为了处理用户的反馈，你必须修改Sdsadlg.rul文件，位于你的InstallShield程序文件夹中的Script/Srt文件夹,<br />5.30  SdShowDlgEdit1<br />语法：SdShowDlgEdit1 (szTitle, szMsg, szField1, svEdit1);<br />说明：SdShowDlgEdit1函数创建一个通用对话框，显示一个消息和一个单行编辑区。你可以为该对话框指定一个标题。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"编辑数据"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。为在该消息包含由先前调用SdProductName设置的产品名称，在该消息的任何地方插入位置夹%P。当消息被显示时，%P由产品名称代替。<br />szField1<br />指定显示在编辑区左边的域名。缺省的域名是"域1："；为显示缺省名称，给该参数传递一个空字符串("")。可以被显示的字符数最大约为10。实际的最大值依赖于域名中每个字符的组合宽度。如果域名超出有效空间，则当对话框被显示时它将从右被截尾。<br />svEdit1<br />指定编辑区的初始值；当对话框被关闭时，返回编辑区的值。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />5.31  SdShowDlgEdit2<br />语法：SdShowDlgEdit2 (szTitle, szMsg, szField1, szField2, svEdit1, svEdit2);<br />说明：SdShowDlgEdit2函数创建一个通用对话框，显示一个消息和两个单行编辑区。你可以为该对话框指定一个标题。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"编辑数据"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。为在该消息包含由先前调用SdProductName设置的产品名称，在该消息的任何地方插入位置夹%P。当消息被显示时，%P由产品名称代替。<br />szField1<br />指定显示在第一个编辑区左边的域名。缺省的域名是"域1："；为显示缺省名称，给该参数传递一个空字符串("")。可以被显示的字符数最大约为10。实际的最大值依赖于域名中每个字符的组合宽度。如果域名超出有效空间，则当对话框被显示时它将从右被截尾。<br />szField2<br />为第二个编辑区指定域名。缺省为"域2："。<br />svEdit1<br />指定第一个编辑区的初始值；当对话框被关闭时，返回第一个编辑区的值。<br />svEdit2<br />指定第二个编辑区的初始值；当对话框被关闭时，返回第二个编辑区的值。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />5.32  SdShowDlgEdit3<br />语法：SdShowDlgEdit3 (szTitle, szMsg, szField1, szField2, szField3, svEdit1, svEdit2, svEdit3);<br />说明：SdShowDlgEdit2函数创建一个通用对话框，显示一个消息和三个单行编辑区。你可以为该对话框指定一个标题。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"编辑数据"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。为在该消息包含由先前调用SdProductName设置的产品名称，在该消息的任何地方插入位置夹%P。当消息被显示时，%P由产品名称代替。<br />szField1<br />指定显示在第一个编辑区左边的域名。缺省的域名是"域1："；为显示缺省名称，给该参数传递一个空字符串("")。可以被显示的字符数最大约为10。实际的最大值依赖于域名中每个字符的组合宽度。如果域名超出有效空间，则当对话框被显示时它将从右被截尾。<br />szField2<br />为第二个编辑区指定域名。缺省为"域2："。<br />szField3<br />为第二个编辑区指定域名。缺省为"域2："。<br />svEdit1<br />指定第一个编辑区的初始值；当对话框被关闭时，返回第一个编辑区的值。<br />svEdit2<br />指定第二个编辑区的初始值；当对话框被关闭时，返回第二个编辑区的值。<br />svEdit3<br />指定第三个编辑区的初始值；当对话框被关闭时，返回第三个编辑区的值。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />5.33  SdShowFileMods<br />语法：SdShowFileMods (szTitle, szMsg, szTargetFile, szAltFile, listChanges, nvSelection);<br />说明：SdShowFileMods函数创建一个对话框，显示你想要对一个文件进行的修改。下面这些选择是有效的：<br />修改目标文件。<br />修改替代文件，它是目标文件的拷贝，但非联合修改。<br />不作任何修改。SdShowFileMods不对文件作修改。你必须使用适当的文件函数把那些修改写入你的脚本。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"修改文件"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串("")。<br />szTargetFile<br />指定要修改的文件名。它将和第一个单选按钮一起显示。<br />szAltFile<br />如果最终用户决定要作修改，指定该文件的替代名。这将和第二个单选按钮一起显示。为使用sztargetFile指定的扩展名为.bak的文件名，给该参数传递一个空字符串（""）。<br />listChanges<br />指定字符串列表名，它包含对文件所作修改的列表。该列表位于一个多行编辑区，允许最终用户选择要实现的修改。<br />nvSelection<br />返回最终用户选择的按钮的ID：<br />101： "让安装修改&lt;szTargetFile&gt;文件。"<br />102： "保存对&lt;szAltFile&gt;所要求的修改。"<br />103： "不作任何修改。"<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />5.34  SdShowInfoList<br />语法：SdShowInfoList (szTitle, szMsg, listID);<br />说明：SdShowInfoList函数创建一个对话框，显示一个可滚动的消息列表。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"信息"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在信息框上方一行的消息。如果消息长于一行，将被从右截尾。如果消息包含一个换行符(\n)，换行符后的文本不被显示。为显示缺省消息（"Text"），给该参数传递一个空字符串("")。<br />listID<br />指定显示在对话框的消息列表。所有显示在对话框的消息为只读。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />BACK (12)：表明单击了Back按钮。<br />注解：<br />·多行编辑区必须为只读。<br />·SdShowInfoList可以显示大约多达57200个字符的列表。<br />5.35  SdShowMsg<br />语法：SdShowMsg (szMsg, bShow);<br />说明：SdShowMsg函数打开或关闭一个小的非模态窗口，显示由szMsg指定的消息。当bShow为TRUE，窗口被打开，消息显示在窗口中，并且继续脚本中下一个语句的处理。注意SdShowMsg窗口被置于安装窗口的中央。当bShow为FALSE时，szMsg被忽略并且关闭SdShowMsg窗口。<br />参数：<br />szMsg<br />指定显示在窗口的消息。为显示缺省消息("安装正查找已安装的组件")，给该参数传递一个空字符串("")。当bShow为FALSE时该参数被忽略。<br />bShow<br />指定是否要打开或关闭窗口。在该参数位置传递下列预定义常量之一：<br />TRUE：如果窗口没有打开则打开它。<br />FALSE：如果窗口打开了则关闭它。<br />返回值：<br />返回值总为0。<br />注解：<br />·SdShowMsg函数提供了一个简单方法使得脚本进程继续的同时，可以将一个显示丰富资料的消息保留在屏幕上。<br />·当SdShowMsg窗口是打开的，随后的对SdShowMsg（第二个参数为TRUE）的调用被忽略。为改变消息，你必须首先以第二个参数为FALSE调用SdShowMsg来关闭窗口，然后以第二个参数为TRUE，szMsg为新的消息再次调用SdShowMsg。<br />·SdShowMsg窗口水平调整大小来在一行上显示szMsg的值。如果消息的长度超过窗口的最大宽度，消息被截尾以适应窗口。<br />·SdShowMsg被设计为单行显示消息。不要在szMag中嵌入换行符(\n)。<br />5.36 SdStartCopy<br />语法：SdStartCopy (szTitle, szMsg, listData);<br />说明：SdStartCopy函数创建一个多行编辑区，显示安装过程中所作的设置和选择。为按需改变设置，用户可以单击对话框的Back按钮来返回到以前的对话框。在检索用户的选择后，开始文件传输处理之前调用SdStartCopy。<br />    使用一个字符串列表来收集安装过程中得到的信息。然后你可以将该字符串列表传递给SdStartCopy的参数listData。SdStartCopy将显示该列表并允许用户在继续文件传输处理之前确认这些信息是正确的。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"开始拷贝文件"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在多行编辑区上方的静态文本区的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串("")。<br />listData<br />指定从最终用户检索得的信息字符串列表。SdStartCopy会自动将每个元素放置到多行编辑区。如果列表为空，该多行编辑区将被隐藏并且只有静态文本区为可见。<br />返回值：<br />NEXT (1)：表明用户选定了Next按钮。<br />BACK (12)：表明用户选定了Back按钮。<br />5.37  SdWelcome<br />语法：SdWelcome (szTitle, szMsg);<br />说明：SdWelcome函数显示一个对话框，欢迎最终用户。<br />参数：<br />szTitle<br />指定显示在对话框标题部分的文本。为显示缺省标题（"欢迎"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在欢迎对话框中的消息。为在该消息中包含先前调用SdProductName而设置的产品名称，在该消息的任意位置插入一个位置夹%P。当该消息被显示时，%P被产品名称代替。为显示缺省欢迎消息（"欢迎进入%P安装程序。该程序将在你的计算机上安装%P"），给该参数传递一个空字符串("")。<br />返回值：<br />NEXT (1)：表明单击了Next按钮。<br />5.38  SdWelcomeMaint<br />语法：SdWelcomeMaint (szTitle, szMsg, nType);<br />说明：SdWelcomeMaint函数显示一个对话框 ，在一个维护型安装（也就是，一个已经被运行的安装的重运行）的开始时使用。该对话框包含修改、修复、删除选项按钮。<br />参数：<br />szTitle<br />指定对话框标题。为显示缺省标题（"欢迎"） ，给该参数传递一个空字符串（""）。<br />szMsg<br />指定显示在对话框的消息。为显示该对话框的缺省指示，给该参数传递一个空字符串("")。<br />nType<br />指定哪个选项按钮为缺省选择。你必须在该参数位置传递下列预定义常量之一，使在对话框中正确显示：<br />MODIFY：修改按钮为缺省选择。<br />REPAIR：修复按钮为缺省选择。<br />REMOVEALL：删除按钮为缺省选择。<br />返回值：<br />MODIFY (301)：表明当单击Next按钮后修改按钮被选定。<br />REPAIR (302)：表明当单击Next按钮后修复按钮被选定。<br />REMOVEALL (303)：表明当单击Next按钮后删除按钮被选定。<br /></span>
<img src ="http://www.cppblog.com/killsound/aggbug/17745.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2007-01-18 11:58 <a href="http://www.cppblog.com/killsound/archive/2007/01/18/17745.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编译VC++时出现的LINK2001的错误及解决</title><link>http://www.cppblog.com/killsound/archive/2007/01/09/17465.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Tue, 09 Jan 2007 09:53:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2007/01/09/17465.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/17465.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2007/01/09/17465.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/17465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/17465.html</trackback:ping><description><![CDATA[
		<font face="Arial" color="#003399" size="4">学习VC＋＋时经常会遇到链接错误LNK2001，该错误非常讨厌，因为对于 <br />编程者来说，最好改的错误莫过于编译错误，而一般说来发生连接错误时， <br />编译都已通过。产生连接错误的原因非常多，尤其LNK2001错误，常常使人不 <br />明其所以然。如果不深入地学习和理解VC＋＋，要想改正连接错误LNK2001非 <br />常困难。 <br />初学者在学习VC＋＋的过程中，遇到的LNK2001错误的错误消息主要为： <br />unresolved external symbol “symbol”（不确定的外部“符号”）。 <br />如果连接程序不能在所有的库和目标文件内找到所引用的函数、变量或 <br />标签，将产生此错误消息。一般来说，发生错误的原因有两个：一是所引用 <br />的函数、变量不存在、拼写不正确或者使用错误；其次可能使用了不同版本 <br />的连接库。 <br />以下是可能产生LNK2001错误的原因： <br />一．由于编码错误导致的LNK2001。 <br />1．不相匹配的程序代码或模块定义（.DEF）文件能导致LNK2001。例如, <br />如果在C＋＋ 源文件内声明了一变量“var1”，却试图在另一文件内以变量 <br />“VAR1”访问该变量,将发生该错误。 <br />2．如果使用的内联函数是在.CPP文件内定义的，而不是在头文件内定 <br />义将导致LNK2001错误。 <br />3．调用函数时如果所用的参数类型同函数声明时的类型不符将会产生 <br />LNK2001。 <br />4．试图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK2001。 <br />5．要注意函数和变量的可公用性，只有全局变量、函数是可公用的。 <br />静态函数和静态变量具有相同的使用范围限制。当试图从文件外部访问 <br />任何没有在该文件内声明的静态变量时将导致编译错误或LNK2001。 <br />函数内声明的变量（局部变量） 只能在该函数的范围内使用。 <br />C＋＋ 的全局常量只有静态连接性能。这不同于C，如果试图在C＋＋的 <br />多个文件内使用全局变量也会产生LNK2001错误。一种解决的方法是需要时在 <br />头文件中加入该常量的初始化代码，并在.CPP文件中包含该头文件；另一种 <br />方法是使用时给该变量赋以常数。 <br />二．由于编译和链接的设置而造成的LNK2001 <br />1．如果编译时使用的是/NOD（/NODEFAULTLIB）选项，程序所需要的运行 <br />库和MFC库在连接时由编译器写入目标文件模块， 但除非在文件中明确包含 <br />这些库名，否则这些库不会被链接进工程文件。在这种情况下使用/NOD将导 <br />致错误LNK2001。 <br />2．如果没有为wWinMainCRTStartup设定程序入口，在使用Unicode和MFC <br />时将得到“unresolved external on _WinMain@16”的LNK2001错误信息。 <br />3．使用/MD选项编译时,既然所有的运行库都被保留在动态链接库之内， <br />源文件中对“func”的引用，在目标文件里即对“__imp__func” 的引用。 <br />如果试图使用静态库LIBC.LIB或LIBCMT.LIB进行连接，将在__imp__func上发 <br />生LNK2001；如果不使用/MD选项编译，在使用MSVCxx.LIB连接时也会发生LNK2001。 <br />4．使用/ML选项编译时，如用LIBCMT.LIB链接会在_errno上发生LNK2001。 <br />5．当编译调试版的应用程序时，如果采用发行版模态库进行连接也会产 <br />生LNK2001；同样，使用调试版模态库连接发行版应用程序时也会产生相同的 <br />问题。 <br />6．不同版本的库和编译器的混合使用也能产生问题，因为新版的库里可 <br />能包含早先的版本没有的符号和说明。 <br />7．在不同的模块使用内联和非内联的编译选项能够导致LNK2001。如果 <br />创建C＋＋库时打开了函数内联（/Ob1或/Ob2），但是在描述该函数的相应头 <br />文件里却关闭了函数内联（没有inline关键字），这时将得到该错误信息。 <br />为避免该问题的发生，应该在相应的头文件中用inline关键字标志内联函数。 <br />8．不正确的/SUBSYSTEM或/ENTRY设置也能导致LNK2001。 <br />其实，产生LNK2001的原因还有很多，以上的原因只是一部分而已，对初 <br />学者来说这些就够理解一阵子了。但是，分析错误原因的目的是为了避免错 <br />误的发生。LNK2001错误虽然比较困难，但是只要注意到了上述问题，还是能 <br />够避免和予以解决的。</font>
<img src ="http://www.cppblog.com/killsound/aggbug/17465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2007-01-09 17:53 <a href="http://www.cppblog.com/killsound/archive/2007/01/09/17465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VS2003/VS2005 常用快捷键</title><link>http://www.cppblog.com/killsound/archive/2007/01/05/17345.html</link><dc:creator>小不懂^_^</dc:creator><author>小不懂^_^</author><pubDate>Fri, 05 Jan 2007 11:19:00 GMT</pubDate><guid>http://www.cppblog.com/killsound/archive/2007/01/05/17345.html</guid><wfw:comment>http://www.cppblog.com/killsound/comments/17345.html</wfw:comment><comments>http://www.cppblog.com/killsound/archive/2007/01/05/17345.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/killsound/comments/commentRss/17345.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/killsound/services/trackbacks/17345.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#ff9966">VS2003/VS2005 常用快捷键</font>
		</p>
		<p>Visual Studio 2003/Visual Studio 2005常用快捷键(快捷方式)</p>
		<p>调试快捷键</p>
		<p>F6: 生成解决方案<br />Ctrl+F6: 生成当前项目<br />F7: 查看代码<br />Shift+F7: 查看窗体设计器<br />F5: 启动调试<br />Ctrl+F5: 开始执行(不调试)<br />Shift+F5: 停止调试<br />Ctrl+Shift+F5: 重启调试<br />F9: 切换断点<br />Ctrl+F9: 启用/停止断点<br />Ctrl+Shift+F9: 删除全部断点<br />F10: 逐过程<br />Ctrl+F10: 运行到光标处<br />F11: 逐语句</p>
		<p>编辑快捷键</p>
		<p>Shift+Alt+Enter: 切换全屏编辑<br />Ctrl+B,T / Ctrl+K,K: 切换书签开关<br />Ctrl+B,N / Ctrl+K,N: 移动到下一书签<br />Ctrl+B,P: 移动到上一书签<br />Ctrl+B,C: 清除全部标签</p>
		<p>Ctrl+I: 渐进式搜索<br />Ctrl+Shift+I: 反向渐进式搜索<br />Ctrl+F: 查找<br />Ctrl+Shift+F: 在文件中查找<br />F3: 查找下一个<br />Shift+F3: 查找上一个<br />Ctrl+H: 替换<br />Ctrl+Shift+H: 在文件中替换<br />Alt+F12: 查找符号(列出所有查找结果)<br />Ctrl+Shift+V: 剪贴板循环</p>
		<p>Ctrl+左右箭头键: 一次可以移动一个单词<br />Ctrl+上下箭头键: 滚动代码屏幕，但不移动光标位置。<br />Ctrl+Shift+L: 删除当前行<br />Ctrl+M,M: 隐藏或展开当前嵌套的折叠状态<br />Ctrl+M,L: 将所有过程设置为相同的隐藏或展开状态<br />Ctrl+M,P: 停止大纲显示<br />Ctrl+E,S: 查看空白<br />Ctrl+E,W: 自动换行<br />Ctrl+G: 转到指定行<br />Shift+Alt+箭头键: 选择矩形文本<br />Alt+鼠标左按钮: 选择矩形文本<br />Ctrl+Shift+U: 全部变为大写<br />Ctrl+U: 全部变为小写</p>
		<p>代码快捷键</p>
		<p>Ctrl+J / Ctrl+K,L: 列出成员<br />Ctrl+Shift+空格键 / Ctrl+K,P: 参数信息<br />Ctrl+K,I: 快速信息<br />Ctrl+E,C / Ctrl+K,C: 注释选定内容<br />Ctrl+E,U / Ctrl+K,U: 取消选定注释内容</p>
		<p>Ctrl+K,M: 生成方法存根<br />Ctrl+K,X: 插入代码段<br />Ctrl+K,S: 插入外侧代码</p>
		<p>F12: 转到所调用过程或变量的定义</p>
		<p>窗口快捷键</p>
		<p>Ctrl+W,W: 浏览器窗口<br />Ctrl+W,S: 解决方案管理器<br />Ctrl+W,C: 类视图<br />Ctrl+W,E: 错误列表<br />Ctrl+W,O: 输出视图<br />Ctrl+W,P: 属性窗口<br />Ctrl+W,T: 任务列表<br />Ctrl+W,X: 工具箱<br />Ctrl+W,B: 书签窗口<br />Ctrl+W,U: 文档大纲</p>
		<p>Ctrl+D,B: 断点窗口<br />Ctrl+D,I: 即时窗口<br />Ctrl+Tab: 活动窗体切换<br />Ctrl+Shift+N: 新建项目<br />Ctrl+Shift+O: 打开项目<br />Ctrl+Shift+S: 全部保存<br />Shift+Alt+C: 新建类<br />Ctrl+Shift+A: 新建项</p>
		<p>
				<br /> </p>
<img src ="http://www.cppblog.com/killsound/aggbug/17345.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/killsound/" target="_blank">小不懂^_^</a> 2007-01-05 19:19 <a href="http://www.cppblog.com/killsound/archive/2007/01/05/17345.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>