﻿<?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>IT博客-D盘-随笔分类-vc</title><link>http://www.cnitblog.com/wufajiaru/category/8081.html</link><description>workspace</description><language>zh-cn</language><lastBuildDate>Wed, 05 Oct 2011 03:38:24 GMT</lastBuildDate><pubDate>Wed, 05 Oct 2011 03:38:24 GMT</pubDate><ttl>60</ttl><item><title>使用VC2005编译静态应用程序的方法</title><link>http://www.cnitblog.com/wufajiaru/archive/2009/07/21/60261.html</link><dc:creator>巴西木</dc:creator><author>巴西木</author><pubDate>Tue, 21 Jul 2009 08:26:00 GMT</pubDate><guid>http://www.cnitblog.com/wufajiaru/archive/2009/07/21/60261.html</guid><wfw:comment>http://www.cnitblog.com/wufajiaru/comments/60261.html</wfw:comment><comments>http://www.cnitblog.com/wufajiaru/archive/2009/07/21/60261.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/wufajiaru/comments/commentRss/60261.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/wufajiaru/services/trackbacks/60261.html</trackback:ping><description><![CDATA[使用1中提到的方法解决了vc8所编译程序不能独立在windows2003上运行的问题。<br><br>转自：<a href="http://hi.baidu.com/hardyheron/blog/item/0a80714575dd883687947387.html">http://hi.baidu.com/hardyheron/blog/item/0a80714575dd883687947387.html</a><br><br><br>
<div class=tit>使用VC2005编译静态应用程序的方法</div>
<div class=date>2009-07-16 18:03</div>
<table style="TABLE-LAYOUT: fixed">
    <tbody>
        <tr>
            <td>
            <div class=cnt id=blog_text>
            <p>使用VC编译C或者C++程序，都需要相关的C runtime库才能运行。如果你是VC6，相应的库就叫MSVCR，如果是VC2005，那就是MSVCR08，VC2008就是MSVCR09。我这 里假设你安装的是VC2005，请进入如下目录：{VS Install Dir}\VC\redist\x86和{System Driver}:\windows\system32，你就会发现下面有很多很多的库。没错，这里相当一部分就是C Runtime库。</p>
            <p>用VC2005编写的Console Win32 C/C++程序，怎么发布给最终用户呢？有两个方法：</p>
            <p>(1) 静态引用C Runtime库</p>
            <p>打开"项目"-&gt;"属性"-&gt;"配置属性"-&gt;"C/C++"-&gt;"代码生成"-&gt;"运行时库 "。这里一共有四个选项，其中MT开头的是静态引用，MD开头的是动态引用，d结尾的是Debug调试版本，没有d的是Release发布版本，所以就一 共有四个选项。</p>
            <p>我们选择/MT（这是默认选项），相应的在"项目"-&gt;"属性"-&gt;"配置属性"-&gt;&#8220;常规&#8221;里选上&#8220;在静态库中使用 MFC&#8221;。然后编译程序（生成的程序应该不小），把这个程序发给用户，然后用户就可以直接运行了。</p>
            <p>如果你是英文版的Visual Studio 2005，则设置这个属性的路径为："Project" --&gt; "Properties" --&gt; "Configuration Properties" --&gt; "C/C++" --&gt; "Code Generation" --&gt; "Runtime Library"。</p>
            <p>(2) 动态引用C Runtime库</p>
            <p>跟上面差不多，不过是用/MD选项编译，然后发给用户。这时，用户是不能运行这个程序的，会报个"程序安装出错，不能运行"、"重装系统可能会修复问题"之类的提示。</p>
            <p>这时我们还要把C Runtime库一并发过去。把{VS Install Dir}\VC\redist\x86\Microsoft.VC80.CRT下的所有文件（注意，是所有，包括那个.manifest文件）发给用户， 用户把这些文件放在我们程序的同一个目录，然后再次运行，这时，程序就起来了。</p>
            <p>第一种是静态编译的方式，第二种是动态编译的方式。静态编译出来的可执行文件会比动态编译出来的大许多，但是用户使用上会方便很多，可以视情况选用。</p>
            <p>如果你有多个工程，请记住把每个工程的配置都设成一致。</p>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cnitblog.com/wufajiaru/aggbug/60261.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/wufajiaru/" target="_blank">巴西木</a> 2009-07-21 16:26 <a href="http://www.cnitblog.com/wufajiaru/archive/2009/07/21/60261.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中对文本文件的读写（iostream方法）[zz]</title><link>http://www.cnitblog.com/wufajiaru/archive/2009/04/15/56390.html</link><dc:creator>巴西木</dc:creator><author>巴西木</author><pubDate>Wed, 15 Apr 2009 05:38:00 GMT</pubDate><guid>http://www.cnitblog.com/wufajiaru/archive/2009/04/15/56390.html</guid><wfw:comment>http://www.cnitblog.com/wufajiaru/comments/56390.html</wfw:comment><comments>http://www.cnitblog.com/wufajiaru/archive/2009/04/15/56390.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/wufajiaru/comments/commentRss/56390.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/wufajiaru/services/trackbacks/56390.html</trackback:ping><description><![CDATA[要写一些简单的日志到文本文件中，参考了以下两篇文章：<br><a title="ifstream 和 ofstream( 引用)" href="http://blog.myspace.cn/e/403372631.htm">ifstream 和 ofstream( 引用)</a><br><a href="http://www.cnblogs.com/coderlee/archive/2008/01/21/1046932.html"><a id=AjaxHolder_ctl01_TitleUrl href="http://www.cnblogs.com/coderlee/archive/2008/01/21/1046932.html">C++标准库 之 iostream库的学习笔记（二）fstream库以及ofstream类的使用</a> <br><br></a><br>
<p>ofstream是从内存到硬盘，ifstream是从硬盘到内存，其实所谓的流缓冲就是内存空间; </p>
<p>在C++中，有一个stream这个类，所有的I/O都以这个&#8220;流&#8221;类为基础的，包括我们要认识的文件I/O，stream这个类有两个重要的运算符： </p>
<p>1、插入器(&lt; &lt; )<br>　　向流输出数据。比如说系统有一个默认的标准输出流(cout)，一般情况下就是指的显示器，所以，cout&lt; &lt; " Write Stdout" &lt; &lt; '\n'; 就表示把字符串" Write Stdout" 和换行字符('\n')输出到标准输出流。 </p>
<p>2、析取器(&gt; &gt; )<br>　　从流中输入数据。比如说系统有一个默认的标准输入流(cin)，一般情况下就是指的键盘，所以，cin&gt; &gt; x; 就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。 </p>
<p>　　在C++中，对文件的操作是通过stream的子类fstream(file stream)来实现的，所以，要用这种方式操作文件，就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。 </p>
<p>一、打开文件<br>　　在fstream类中，有一个成员函数open()，就是用来打开文件的，其原型是： </p>
<p>void open(const char* filename,int mode,int access); </p>
<p>参数： </p>
<p>filename：　　要打开的文件名<br>mode：　　　　要打开文件的方式<br>access：　　　打开文件的属性<br>打开文件的方式在类ios(是所有流式I/O类的基类)中定义，常用的值如下： </p>
<p>ios::app：　　　以追加的方式打开文件<br>ios::ate：　　　文件打开后定位到文件尾，ios:app就包含有此属性<br>ios::binary： 　以二进制方式打开文件，缺省的方式是文本方式。两种方式的区别见前文<br>ios::in：　　　 文件以输入方式打开（文件数据输入到内存）<br>ios::out：　　　文件以输出方式打开（内存数据输出到文件）<br>ios::nocreate： 不建立文件，所以文件不存在时打开失败<br>ios::noreplace：不覆盖文件，所以打开文件时如果文件存在失败<br>ios::trunc：　　如果文件存在，把文件长度设为0<br>　　可以用&#8220;或&#8221;把以上属性连接起来，如ios::out|ios::binary </p>
<p>　　打开文件的属性取值是： </p>
<p>0：普通文件，打开访问<br>1：只读文件<br>2：隐含文件<br>4：系统文件<br>　　可以用&#8220;或&#8221;或者&#8220;+&#8221;把以上属性连接起来 ，如3或1|2就是以只读和隐含属性打开文件。 </p>
<p>　　例如：以二进制输入方式打开文件c:\config.sys<br>fstream file1; <br>file1.open(" c:\\config.sys" ,ios::binary|ios::in,0); </p>
<p>　　如果open函数只有文件名一个参数，则是以读/写普通文件打开，即：<br>file1.open(" c:\\config.sys" ); &lt; =&gt; file1.open(" c:\\config.sys" ,ios::in|ios::out,0); </p>
<p>　　另外，fstream还有和open()一样的构造函数，对于上例，在定义的时侯就可以打开文件了：<br>fstream file1(" c:\\config.sys" ); </p>
<p>　　特别提出的是，fstream有两个子类：ifstream(input file stream)和ofstream(outpu file stream)，ifstream默认以输入方式打开文件，而ofstream默认以输出方式打开文件。<br>ifstream file2(" c:\\pdos.def" ); //以输入方式打开文件<br>ofstream file3(" c:\\x.123" ); //以输出方式打开文件 </p>
<p>　　所以，在实际应用中，根据需要的不同，选择不同的类来定义：如果想以输入方式打开，就用ifstream来定义；如果想以输出方式打开，就用ofstream来定义；如果想以输入/输出方式来打开，就用fstream来定义。 </p>
<p>二、关闭文件<br>　　打开的文件使用完成后一定要关闭，fstream提供了成员函数close()来完成此操作，如：file1.close(); 就把file1相连的文件关闭。 </p>
<p>三、读写文件<br>　　读写文件分为文本文件和二进制文件的读取，对于文本文件的读取比较简单，用插入器和析取器就可以了；而对于二进制的读取就要复杂些，下要就详细的介绍这两种方式 </p>
<p>　　1、文本文件的读写<br>　　文本文件的读写很简单：用插入器(&lt; &lt; )向文件输出；用析取器(&gt; &gt; )从文件输入。假设file1是以输入方式打开，file2以输出打开。示例如下： </p>
<p>　　file2&lt; &lt; " I Love You" ; //向文件写入字符串" I Love You" <br>　　int i; <br>　　file1&gt; &gt; i; //从文件输入一个整数值。 </p>
<p>　　这种方式还有一种简单的格式化能力，比如可以指定输出为16进制等等，具体的格式有以下一些 </p>
<p>操纵符 功能 输入/输出<br>dec 格式化为十进制数值数据 输入和输出<br>endl 输出一个换行符并刷新此流 输出<br>ends 输出一个空字符 输出<br>hex 格式化为十六进制数值数据 输入和输出<br>oct 格式化为八进制数值数据 输入和输出<br>setpxecision(int p) 设置浮点数的精度位数 输出 </p>
<p>　　比如要把123当作十六进制输出：file1&lt; &lt; hex&lt; &lt; 123; 要把3.1415926以5位精度输出：file1&lt; &lt; setpxecision(5)&lt; &lt; 3.1415926。 </p>
<p>　　2、二进制文件的读写<br>①put()<br>　　put()函数向流写入一个字符，其原型是ofstream &amp;put(char ch)，使用也比较简单，如file1.put('c'); 就是向流写一个字符'c'。 </p>
<p>②get()<br>　　get()函数比较灵活，有3种常用的重载形式： </p>
<p>　　一种就是和put()对应的形式：ifstream &amp;get(char &amp; ch); 功能是从流中读取一个字符，结果保存在引用ch中，如果到文件尾，返回空字符。如file2.get(x); 表示从文件中读取一个字符，并把读取的字符保存在x中。 </p>
<p>　　另一种重载形式的原型是： int get(); 这种形式是从流中返回一个字符，如果到达文件尾，返回EOF，如x=file2.get(); 和上例功能是一样的。 </p>
<p>　　还有一种形式的原型是：ifstream &amp;get(char *buf,int num,char delim='\n')；这种形式把字符读入由 buf 指向的数组，直到读入了 num 个字符或遇到了由 delim 指定的字符，如果没使用 delim 这个参数，将使用缺省值换行符'\n'。例如： </p>
<p>　　file2.get(str1,127,'A'); &nbsp; &nbsp; //从文件中读取字符到字符串str1，当遇到字符'A'或读取了127个字符时终止。 </p>
<p>③读写数据块<br>　　要读写二进制数据块，使用成员函数read()和write()成员函数，它们原型如下： </p>
<p>　　　　read(unsigned char *buf,int num); <br>　　　　write(const unsigned char *buf,int num); </p>
<p>　　read()从文件中读取 num 个字符到 buf 指向的缓存中，如果在还未读入 num 个字符时就到了文件尾，可以用成员函数 int gcount(); 来取得实际读取的字符数；而 write() 从buf 指向的缓存写 num 个字符到文件中，值得注意的是缓存的类型是 unsigned char *，有时可能需要类型转换。 </p>
<p>例： </p>
<p>　　　　unsigned char str1[]=" I Love You" ; <br>　　　　int n[5]; <br>　　　　ifstream in(" xxx.xxx" ); <br>　　　　ofstream out(" yyy.yyy" ); <br>　　　　out.write(str1,strlen(str1)); //把字符串str1全部写到yyy.yyy中<br>　　　　in.read((unsigned char*)n,sizeof(n)); //从xxx.xxx中读取指定个整数，注意类型转换<br>　　　　in.close(); out.close(); </p>
<p>四、检测EOF<br>　　成员函数eof()用来检测是否到达文件尾，如果到达文件尾返回非0值，否则返回0。原型是int eof(); </p>
<p>例：　　if(in.eof())&nbsp; &nbsp; ShowMessage(" 已经到达文件尾！" ); </p>
<p>五、文件定位<br>　　和C的文件操作方式不同的是，C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针，它说明输入操作在文件中的位置；另一个是写指针，它下次写操作的位置。每次执行输入或输出时，相应的指针自动变化。所以，C++的文件定位分为读位置和写位置的定位，对应的成员函数是seekg()和seekp()。seekg()是设置读位置，seekp是设置写位置。它们最通用的形式如下： </p>
<p>　　　　istream &amp;seekg(streamoff offset,seek_dir origin); <br>　　　　ostream &amp; seekp(streamoff offset,seek_dir origin); </p>
<p>　　streamoff定义于 iostream.h 中，定义有偏移量 offset 所能取得的最大值，seek_dir 表示移动的基准位置，是一个有以下值的枚举： </p>
<p>ios::beg：　　文件开头<br>ios::cur：　　文件当前位置<br>ios::end：　　文件结尾 </p>
<p>　　这两个函数一般用于二进制文件，因为文本文件会因为系统对字符的解释而可能与预想的值不同。例： </p>
<p>　　　file1.seekg(1234,ios::cur); &nbsp; &nbsp; //把文件的读指针从当前位置向后移1234个字节<br>　　　file2.seekp(1234,ios::beg); &nbsp; &nbsp; //把文件的写指针从文件开头向后移1234个字节 </p>
<br><br>
<div class=postTitle><a id=AjaxHolder_ctl01_TitleUrl href="http://www.cnblogs.com/coderlee/archive/2008/01/21/1046932.html"><font color=#000080>C++标准库 之 iostream库的学习笔记（二）fstream库以及ofstream类的使用</font></a> </div>
<div class=postText>
<p>iostream库不仅支持终端设备的输入输出，还支持文件的输入输出，和文件有关的输入输出类声明在fstream头文件中，有三个类负责文件的输入输出<br></p>
<p>1) ifstream类:从istream类派生。<br>2) ofstream类:从ostream类派生。<br>3) fstream类:从iostream类派生。<br></p>
<p>由于文件的输入输出和键盘鼠标的输入输出是不一样的，一般pc机只有一个键盘设备，所以iostream库内部声明了一个istream类的对象cin，这个对象负责从键盘获取数据，而文件设备在系统中是由许多的，所以iostream库内部无法给你为机器的每个文件都创建一个负责获取数据的ifstream对象和负责写入数据的ofstream对象，所以我们要针对一个文件进行读取或写入数据的时候都要自己创建一个ifstream或ostream类的对象来用。</p>
<p>ofstream类的默认构造函数如下:</p>
<div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: rgb(0,0,0)">ofstream::ofstream(</span><span style="COLOR: rgb(0,0,255)">const</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,255)">char</span><span style="COLOR: rgb(0,0,0)">*</span><span style="COLOR: rgb(0,0,0)">&nbsp;filename,&nbsp;</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)">&nbsp;mode&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;ios::</span><span style="COLOR: rgb(0,0,255)">out</span><span style="COLOR: rgb(0,0,0)">,&nbsp;</span><span style="COLOR: rgb(0,0,255)">int</span><span style="COLOR: rgb(0,0,0)">&nbsp;openport&nbsp;</span><span style="COLOR: rgb(0,0,0)">=</span><span style="COLOR: rgb(0,0,0)">&nbsp;filebuf::openport);</span></div>
<p>filename是要打开的文件名，<br>mode是打开的方式，<br>openport是打开文件的属性。<br><br>mode可以设置的方式如下：<br>ios::app&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以追加的方式打开<br>ios::ate&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;文件打开后定位到文件尾<br>ios::binary&nbsp;&nbsp;&nbsp;&nbsp;以二进制方式打开文件，默认是以文本方式打开<br>ios::in&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;文件以读(输入)方式打开<br>ios::out&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 文件以写(输出)方式打开<br>ios::trunc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果文件存在，则把文件清空。<br>以上属性用&#8220;|&#8221;(按位或)连接起来。<br></p>
<p>openprot属性如下：<br>0&nbsp;&nbsp;&nbsp;&nbsp;普通文件<br>1&nbsp;&nbsp;&nbsp;&nbsp;只读文件<br>2&nbsp;&nbsp;&nbsp;&nbsp;隐含文件<br>4&nbsp;&nbsp;&nbsp;&nbsp;系统文件<br>以上属性可以用加或者按位或方式组织起来，比如1|2和3都代表既是只读又是隐含文件。<br><br>在windows操作系统中可以不要第三个参数，如果加入第三个参数，那第三个参数是打开文件的共享方式，也就是打开这个文件时，其他进程是否可以读写该文件。<br>共享方式参数可以是下面的值：<br>0x10 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //_SH_DENYRW &nbsp; Denies &nbsp; read &nbsp; and &nbsp; write &nbsp; access &nbsp; to &nbsp; the &nbsp; file <br>0x20 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //_SH_DENYWR &nbsp; Denies &nbsp; write &nbsp; access &nbsp; to &nbsp; the &nbsp; file <br>0x30 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //_SH_DENYRD &nbsp; Denies &nbsp; read &nbsp; access &nbsp; to &nbsp; the &nbsp; file. <br>0x40 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //_SH_DENYNO &nbsp; Permits &nbsp; read &nbsp; and &nbsp; write &nbsp; access &nbsp; <br>其他值都会报 "Invalid &nbsp; sharing &nbsp; flag "的错误。 </p>
<div style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;ofstream&nbsp;hFile(</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(128,0,0)">c:\\1.txt</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(0,0,0)">,&nbsp;ios::</span><span style="COLOR: rgb(0,0,255)">out</span><span style="COLOR: rgb(0,0,0)">,&nbsp;_SH_DENYRW);&nbsp;</span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)">&nbsp;_SH_DENYRW&nbsp;is&nbsp;deny&nbsp;read&nbsp;and&nbsp;write</span><span style="COLOR: rgb(0,128,0)"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">if</span><span style="COLOR: rgb(0,0,0)">&nbsp;(</span><span style="COLOR: rgb(0,0,0)">!</span><span style="COLOR: rgb(0,0,0)">hFile)&nbsp;</span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)">&nbsp;if&nbsp;the&nbsp;file&nbsp;could&nbsp;open,&nbsp;hFile&nbsp;is&nbsp;a&nbsp;handle,&nbsp;else&nbsp;is&nbsp;zero</span><span style="COLOR: rgb(0,128,0)"><br><img id=Codehighlighter1_166_311_Open_Image style="DISPLAY: inline" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_166_311_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_166_311_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_166_311_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_166_311_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_166_311_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_166_311_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_166_311_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_166_311_Closed_Text style="BORDER-RIGHT: rgb(128,128,128) 1px solid; BORDER-TOP: rgb(128,128,128) 1px solid; DISPLAY: none; BORDER-LEFT: rgb(128,128,128) 1px solid; BORDER-BOTTOM: rgb(128,128,128) 1px solid; BACKGROUND-COLOR: rgb(255,255,255)"><img alt="" src="http://www.cnblogs.com/Images/dot.gif"></span><span id=Codehighlighter1_166_311_Open_Text style="DISPLAY: inline"><span style="COLOR: rgb(0,0,0)">{<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(128,0,0)">write&nbsp;fail!</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">&nbsp;endl;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(128,0,0)">access&nbsp;is&nbsp;denies,maybe&nbsp;the&nbsp;file&nbsp;is&nbsp;readonlys,or&nbsp;use&nbsp;deny&nbsp;read&nbsp;opened&nbsp;of&nbsp;other&nbsp;process.</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">&nbsp;endl;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: rgb(0,0,0)"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: rgb(0,0,255)">else</span><span style="COLOR: rgb(0,0,0)"><br><img id=Codehighlighter1_319_392_Open_Image style="DISPLAY: inline" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_319_392_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_319_392_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_319_392_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_319_392_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_319_392_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_319_392_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_319_392_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_319_392_Closed_Text style="BORDER-RIGHT: rgb(128,128,128) 1px solid; BORDER-TOP: rgb(128,128,128) 1px solid; DISPLAY: none; BORDER-LEFT: rgb(128,128,128) 1px solid; BORDER-BOTTOM: rgb(128,128,128) 1px solid; BACKGROUND-COLOR: rgb(255,255,255)"><img alt="" src="http://www.cnblogs.com/Images/dot.gif"></span><span id=Codehighlighter1_319_392_Open_Text style="DISPLAY: inline"><span style="COLOR: rgb(0,0,0)">{<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hFile&nbsp;</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(128,0,0)">by&nbsp;coderlee&nbsp;writes</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(0,0,0)">;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(128,0,0)">write&nbsp;success!</span><span style="COLOR: rgb(128,0,0)">"</span><span style="COLOR: rgb(0,0,0)">&nbsp;</span><span style="COLOR: rgb(0,0,0)">&lt;&lt;</span><span style="COLOR: rgb(0,0,0)">&nbsp;endl;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: rgb(0,0,0)"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;hFile.close();&nbsp;</span><span style="COLOR: rgb(0,128,0)">//</span><span style="COLOR: rgb(0,128,0)">&nbsp;opened&nbsp;file&nbsp;need&nbsp;close.</span><span style="COLOR: rgb(0,128,0)"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>上面是写文件的事例代码，先打开文件，然后判断是不是0，如果是0，则提示write fail否则写文件，提示write success.<br></p>
</div>
<br><br>
<img src ="http://www.cnitblog.com/wufajiaru/aggbug/56390.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/wufajiaru/" target="_blank">巴西木</a> 2009-04-15 13:38 <a href="http://www.cnitblog.com/wufajiaru/archive/2009/04/15/56390.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用 C++ 创建简单的 Win32 服务程序[zz]</title><link>http://www.cnitblog.com/wufajiaru/archive/2009/04/13/56323.html</link><dc:creator>巴西木</dc:creator><author>巴西木</author><pubDate>Mon, 13 Apr 2009 08:41:00 GMT</pubDate><guid>http://www.cnitblog.com/wufajiaru/archive/2009/04/13/56323.html</guid><wfw:comment>http://www.cnitblog.com/wufajiaru/comments/56323.html</wfw:comment><comments>http://www.cnitblog.com/wufajiaru/archive/2009/04/13/56323.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/wufajiaru/comments/commentRss/56323.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/wufajiaru/services/trackbacks/56323.html</trackback:ping><description><![CDATA[<p align=center><strong>用 C++ 创建简单的 Win32 服务程序<br></strong><br>作者：Nigel Thomson（MSDN 技术组）<br>翻译：<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#110;&#111;&#114;&#116;&#104;&#116;&#105;&#98;&#101;&#116;&#64;&#115;&#111;&#104;&#117;&#46;&#99;&#111;&#109;"><u><font color=#0000ff>NorthTibet</font></u></a></p>
<p>原文出处：<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_ntservic.asp" target=_blank><u><font color=#0000ff>Creating a Simple Win32 Service in C++</font></u></a><br><br>下载 <a href="http://www.vckbase.com/code/downcode.asp?id=2668"><u><font color=#0000ff>NTService</font></u></a> 例子源代码<br>下载 <a href="http://www.vckbase.com/code/downcode.asp?id=2669"><u><font color=#0000ff>NTServCpl</font></u></a> 例子源代码<br>下载 <a href="http://www.vckbase.com/code/downcode.asp?id=2670"><u><font color=#0000ff>NTServCtrl</font></u></a> 例子源代码<br><br><img src="http://www.vckbase.com/document/image/paragraph.gif"> <strong>摘要</strong><br><br>　　本文描述如何用 Visual C++ 创建 Windows NT 服务程序。创建该服务仅用到一个 C++ 类，这个类提供服务与操作系统之间一个简单的接口。使用这个类实现自己的服务非常简单，只要改写少数几个基类中的虚拟函数即可。在本文有三个源代码参考例子：
<ul>
    <li>NTService 是一个简单的 Win32 服务，它就是用本文所描述的方法建立的；
    <li>NTServCpl 是一个控制面版程序，用来控制 NTService 服务；
    <li>NTServCtrl 是一个独立的程序例子，用它可以监控某个 Win32 服务； </li>
</ul>
<p><img src="http://www.vckbase.com/document/image/paragraph.gif"> <strong>简介</strong><br><br>　　Windows NT 中的服务实际上是一个程序，只要计算机操作系统一启动，服务就可以运行其中。它不需要用户登陆。服务程序是一种与用户无关的任务，比如目录复制，进程监控或网络上供其它机器使用的服务，比如 HTTP 协议支持。<br>　　创建&nbsp;Windows NT 服务程序并不是很难。但调试某个服务程序不是一件容易的事。就我自己而言，我喜欢用 Visual C++ 编写自己的 C++ 程序。大多数 Win32 服务都是用 C 写的，所以我觉得如果用某个 C++ 类来实现 Win32 服务的基本功能一定很有意思。有了这个 C++ 类，谁要想用 C++ 创建 Win32 服务就是一件很简单的事情了。我为此开发了一个 C++ 基类，用它作为编写 Win32 服务的起点应该没有什么大问题。<br><br>创建服务程序除了编写服务代码外，还必须做一些其它额外的编码工作：
<ul>
    <li>在系统日志或应用程序日志中报告警告信息和出错信息，不能用输出到屏幕的方式，因为用户根本就没有登陆。
    <li>服务程序的控制即可以通过单独的应用程序，也可以通过控制面版程序。这取决于你的服务实现什么样的通讯机制。
    <li>从系统中安装和卸载服务 </li>
</ul>
<p>　　大多数服务程序都是使用一个安装程序来安装，而用另外一个程序来卸载。本文我将这些功能内建在服务程序自身当中，使之一体化，这样只分发一个.EXE文件即可。你可以从命令行直接运行服务程序，并且可以随心所欲地安装和卸载或报告其版本信息。NTService 支持下列的命令行参数：
<ul>
    <li>-v, 报告服务的名字和版本号；
    <li>-i, 安装服务；
    <li>-u, 卸载服务； </li>
</ul>
<p>默认情况下，当系统启动该服务时没有命令行参数传递。<br><br><img src="http://www.vckbase.com/document/image/paragraph.gif"> <strong>创建应用程序框架</strong><br><br>　　我一直都是创建基于 MFC 的应用程序。当我刚接触 Win32 服务程序时，我先是用 Visual C++ AppWizard 创建一个 SDI/MFC 程序。然后去掉其中的文档和视图类、图标以及其它一些无用的东西，只剩下框架。结果到最后什么都去掉了，包括主窗口（服务程序不能有这个东东），什么也没有留下，非常愚蠢。我不得不 又回过头到 AppWizard，并用单个的源文件创建控制台程序，此源文件包含main 入口函数，我将这个文件命名为 NTServApp.cpp。我用此 cpp 扩展而不是用 C，因为我只想用C++ 来写程序，而不是直接用 C。稍后我们会讨论该文件代码实现。<br>　　因为我想用 C++ 类来构建服务，所以我创建了 NTService.h 和 NTService.cpp 文件，用它们来实现 CNTService 基类。我还创建了 MyService.h 和 MyService.cpp 文件用于实现自己的服务类（CMyService），它派生于 CNTService。稍后我们会看到代码。<br>　　建立新工程时，我喜欢尽快看到运行结果，所以我决定服务程序要做的第一件事情是建立一个系统应用程序日志记录。借助这个日志记录机制，我能跟踪服务何时启动， 何时停止等等。我还可以记录服务中发生的任何出错信息。创建这个日志记录比我想象的要复杂得多。<br><br><img src="http://www.vckbase.com/document/image/paragraph.gif"> <strong>建立日志记录</strong><br>　　我想，既然日志文件是操作系统的一部分，那么肯定有应用程序编程接口（API）来支持建立日志记录。所以我开始搜索 MSDN CD，直到发现 ReportEvent 函数为止。如果你不熟悉这个函数，你可能会想，这个函数应该知道在哪个日志文件建立记录，以及你想要插入的文本信息。没错，这都是它要做的事情，但是为了简化出错信息的国际化，该函数有一个消息 ID 作为参数，并在你提供的消息表中查找消息。所以问题无非是你想将什么消息放入日志，以及如何将这些消息添加到你的应用程序中，下面我们一步一步来做： </p>
<ol>
    <li>以 .MC 为扩展名创建一个包含消息描述的文本文件。我将它命名为 NTServMsg.mc。该文件的格式非常特别，具体细节参见 Platform SDK 文档；
    <li>针对你的源文件运行消息编译器（mc.exe），默认情况下它创建名为 MSG00001.BIN 的输出文件。编译器还创建一个头文件（在我的例子程序中，该头文件是 NTServMsg.h）和一个.RC 文件（NTServMsg.rc）。只要你修改工程的 .MC 文件就必须重复这一步，所以把工具加到 Visual C++ 的工具菜单里做起来会很方便；
    <li>为工程创建一个 .RC 文件，将 WINDOWS.H 头文件以及消息编译器产生的 .RC 文件包含到其中；
    <li>在主工程头文件中包含消息编译器产生的头文件，以便模块可以存取符号消息名； </li>
</ol>
<p>　　下面让我们仔细一下这些文件，以便弄明白你自己需要创建什么，以及消息编译器要为你创建些什么。我们不用研究整个消息集，只要看看其中一二个如何工作的即可。下面是例子程序消息源文件 NTServMsg.mc 的第一部分：</p>
<pre>MessageId=100
SymbolicName=EVMSG_INSTALLED
Language=English
The %1 service was installed.
.
MessageId=
SymbolicName=EVMSG_REMOVED
Language=English
The %1 service was removed.
.
MessageId=
SymbolicName=EVMSG_NOTREMOVED
Language=English
The %1 service could not be removed.
.</pre>
<p>　　每一条都有一个消息ID，如果不特别设置，那么 ID 的取值就是指其前面所赋的值。每一条还有一个代码中使用的符号名，语言标示符以及消息文本。消息可以跨多个行，并用含有一个句号的单独一行终止。<br>　　消息编译器输出一个库文件，该库文件被用作应用程序的资源，此外还输出两个要在代码中包含的文件。下面是我的 .RC 文件：</p>
<pre>// NTServApp.rc
#include &lt;windows.h&gt;
// 包含由消息编译器（MC）产生的消息表资源脚本
#include "NTServMsg.rc"
Here''s the .RC file the message compiler generated:
LANGUAGE 0x9,0x1
1 11 MSG00001.bin</pre>
<p>正像你所看到的，这些文件中内容不多!<br><br>消息编译器产生的最后一个文件是你要包含到代码中的头文件，下面就是这个头文件的部分内容：</p>
<pre>[..........]
//
// MessageId: EVMSG_INSTALLED
//
// MessageText:
//
// The %1 service was installed.
//
#define EVMSG_INSTALLED 0x00000064L
//
// MessageId: EVMSG_REMOVED
//
// MessageText:
//
// The %1 service was removed.
//
#define EVMSG_REMOVED 0x00000065L
[...........]</pre>
<p>　　你可能已经注意到了有几个消息包含参数替代项（如 %1）。让我们看看将消息写入某个系统日志文件时如何在代码中使用消息ID和参数替代项。以事件日志中记录成功安装信息的部分安装代码为例。也就是 CNTService::IsInstalled 函数部分：</p>
<pre>[....]
LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_INSTALLED, m_szServiceName);
[....]</pre>
<p>LogEvent 是另一个 CNTService 函数，它使用事件类型（信息，警告或错误），事件消息的 ID，以及形成日志消息的最多三个参数的替代串：</p>
<pre>// This function makes an entry into the application event log.
void CNTService::LogEvent(WORD wType, DWORD dwID,
const char* pszS1,
const char* pszS2,
const char* pszS3)
{
const char* ps[3];
ps[0] = pszS1;
ps[1] = pszS2;
ps[2] = pszS3;
int iStr = 0;
for (int i = 0; i &lt; 3; i++) {
if (ps[i] != NULL) iStr++;
}
// Check to see if the event source has been registered,
// and if not then register it now.
if (!m_hEventSource) {
m_hEventSource = ::RegisterEventSource(NULL, // local machine
m_szServiceName); // source name
}
if (m_hEventSource) {
::ReportEvent(m_hEventSource,
wType,
0,
dwID,
NULL, // sid
iStr,
0,
ps,
NULL);
}
}		</pre>
如你所见，其主要工作是由 ReportEvent 系统函数处理。<br><br>　　至此，我们已经可以通过调用 CNTService::LogEvent 在系统日志中记录事件了。接下来我们将考虑创建服务本身的一些代码。<br><br><img src="http://www.vckbase.com/document/image/paragraph.gif"><strong> 编写服务代码</strong><br><br>　　为了建构一个简单的 Win32 服务，你需要知道的大多数信息都可以在 Platform SDK 中找到。其中的范例代码都是用C语言写的，并且很好理解。我的 CNTService 类就是基于这些代码。<br><br>一个服务主要包括三个函数：
<ul>
    <li>main函数，这是代码的入口。我们正是在这里解析任何命令行参数并进行服务的安装，移除，启动等等。
    <li>在例子中，提供真正服务代码的入口函数叫 ServiceMain。你可以随便叫它什么。在服务第一次启动的恶时候，将该函数的地址传递给服务管理器。
    <li>处理来自服务管理器命令消息的函数。在例子中，这个函数叫 Handler，这个名字可以随意取。 </li>
</ul>
<p><em>服务回调函数</em><br>　　因为 ServiceMain 和 Handler 函数都是由系统来调用，所以它们必须遵循操作系统的参数传递规范和调用规范。也就是说，它们不能简单地作为某个 C++ 类的成员函数。这样就给封装带来一些不便，因为我们想把 Win32 服务的功能封装在一个 C++ 类中。为了解决这个问题，我将 ServiceMain 和 Handler 函数创建成 CNTService 类的静态成员。这样就使我得以创建可以由操作系统调用的函数。 但是，这样做还没有完全解决问题，因为系统不允许给被调用的函数传递任何形式的用户数据，所以我们无法确定对 C++ 对象特定实例的 ServiceMain 或 Handler 的调用。用了一个非常简单但有局限的方法来解决这个问题。我创建一个包含 C++ 对象指针的静态变量。这个变量是在该对象首次创建是进行初始化的。这样便限制你每个服务应用只有一个C++对象。我觉得这个限制并不过分。下面是 NTService.h 文件中的声明：</p>
<pre>class CNTService
{
[...]
// 静态数据
static CNTService* m_pThis; // nasty hack to get object ptr
[...]
};</pre>
<p>下面是初始化 m_pThis 指针的方法：</p>
<pre>CNTService::CNTService(const char* szServiceName)
{
// Copy the address of the current object so we can access it from
// the static member callback functions.
// WARNING: This limits the application to only one CNTService object.
m_pThis = this;
[...]
}</pre>
<p><img src="http://www.vckbase.com/document/image/paragraph.gif"><strong> CNTService 类</strong><br><br>　　当我创建 C++ 对象封装 Windows 函数时，我尝试为我封装的每个 Windows API 除了创建成员函数外，还做一些别的工作，我尝试让对象更容易使用，降低实现特定项目所需的代码行数。因此我的对象是基于&#8220;我想让这个对象做什么？&#8221;而不是&#8220;Windows 用这些 APIs 做什么？&#8221;<br>　　CNTService 类包含一些用来解析命令行的成员函数，为了处理服务的安装和拆卸以及事件日志的记录，你得在派生类中重写一些虚拟函数来处理服务控制管理器的请求。下面我们将通过本文的例子服务实现来研究这些函数的使用。<br>　　如果你想创建尽可能简单的服务，只需要重写 CNTService::Run 即可，它是你编写代码实现具体服务任务的地方。你还需要实现 main 函数。如果服务需要实现一些初始化。如从注册表读取数据，还需重写 CNTService::OnInit。如果你要向服务发送命令消息 ，那么可以在服务中使用系统函数 ControlService，重写 CNTService::OnUserControl 来处理请求。<br><br><em>在例子应用程序中使用 CNTService</em> <br>　　NTService 在 CMyService 类中实现了它的大多数功能，CMyService 由 CNTService 派生。 MyService.h 头文件如下：</p>
<pre>// myservice.h
#include "ntservice.h"
class CMyService : public CNTService
{
public:
CMyService();
virtual BOOL OnInit();
virtual void Run();
virtual BOOL OnUserControl(DWORD dwOpcode);
void SaveStatus();
// Control parameters
int m_iStartParam;
int m_iIncParam;
// Current state
int m_iState;
};</pre>
<p>　　正像你所看到的，CMyService 改写了 CNTService 的 OnInit、Run 和 OnUserControl。它还有一个函数叫 SaveStatus，这个函数被用于将数据写入注册表，那些成员变量用来保存当前状态。例子服务每隔一定的时间对一个整型变量进行增量处理。开始值和增量值都存在注册表的参数中。这样做并没有别的意图。只是为了简单示范。下面我们看看这个服务是如何实现的。<br><br><img src="http://www.vckbase.com/document/image/paragraph.gif"><strong> 实现 main 函数</strong><br><br>有了从 CNTService 派生的 CMyService，实现 main 函数很简单，请看 NTServApp.cpp 文件：</p>
<pre>int main(int argc, char* argv[])
{
// 创建服务对象
CMyService MyService;
// 解析标准参数 (安装, 卸载, 版本等.)
if (!MyService.ParseStandardArgs(argc, argv)) {
// 未发现任何标准参数，所以启动服务，
// 取消下面 DebugBreak 代码行的注释，
// 当服务启动后进入调试器，
//DebugBreak();
MyService.StartService();
}
// 到这里，服务已经停止
return MyService.m_Status.dwWin32ExitCode;
}		</pre>
　　这里代码不多，但执行后却发生了很多事情，让我们一步一步来看。首先，我们创建一个 MyService 类的实例。构造函数设置初始化状态和服务名字（MyService.cpp）：
<pre>CMyService::CMyService():CNTService("NT Service Demonstration")
{
m_iStartParam = 0;
m_iIncParam = 1;
m_iState = m_iStartParam;
}</pre>
<p>　　接着调用 ParseStandardArgs 检查命令行是否包含服务安装（-i）、卸载（-u）以及报告其版本号（-v）的请求。CNTService::ParseStandardArgs 分别调用 CNTService::IsInstalled，CNTService::Install 和 CNTService::Uninstall 来处理这些请求。如果没有可识别的命令行参数，则假设该服务控制管理器试图启动该服务并调用 StartService。该函数直到服务停止运行才返回。当你调试完代码，即可把用于调试的代码行注释掉或删除。<br><br><em>安装和卸载服务</em><br>　　服务的安装由 CNTService::Install 处理，它用 Win32 服务管理器注册服务并在注册表中建立一个条目以支持服务运行时日志消息。<br>　　服务的卸载由 CNTService::Uninstall 处理，它仅仅通知服务管理器该服务已经不再需要。CNTService::Uninstall 不会删除服务实际的可执行文件。<br><br><img src="http://www.vckbase.com/document/image/paragraph.gif"><strong> 编写服务代码</strong><br><br>　　现在我们来编写实现服务的具体代码。对于 NTService 例子，有三个函数要写。他们涉及初始化，运行服务的细节和响应控制请求。<br><br><em>初始化</em><br>　　注册表有一个给服务用来存储参数的地方：</p>
<pre>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services</pre>
<p>　　我就是选择这里来存储我的服务配置信息。我创建了一个 Parameters 键，并在此存储我要保存的值。所以当服务启动时，OnInit 函数被调用；这个函数从注册表中读取初始设置。</p>
<pre>BOOL CMyService::OnInit()
{
// Read the registry parameters.
// Try opening the registry key:
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<appname>\Parameters
HKEY hkey;
char szKey[1024];
strcpy(szKey, "SYSTEM\\CurrentControlSet\\Services\\");
strcat(szKey, m_szServiceName);
strcat(szKey, "\\Parameters");
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szKey,
0,
KEY_QUERY_VALUE,
&amp;hkey) == ERROR_SUCCESS) {
// Yes we are installed.
DWORD dwType = 0;
DWORD dwSize = sizeof(m_iStartParam);
RegQueryValueEx(hkey,
"Start",
NULL,
&amp;dwType,
(BYTE*)&amp;m_iStartParam,
&amp;dwSize);
dwSize = sizeof(m_iIncParam);
RegQueryValueEx(hkey,
"Inc",
NULL,
&amp;dwType,
(BYTE*)&amp;m_iIncParam,
&amp;dwSize);
RegCloseKey(hkey);
}
// Set the initial state.
m_iState = m_iStartParam;
return TRUE;
}		</pre>
现在我们有了服务参数，我们便可以运行服务了。<br><br><em>运行服务</em><br>当 Run 函数被调用时将执行服务的主体代码。本文例子的这部分很简单：
<pre>void CMyService::Run()
{
while (m_bIsRunning) {
// Sleep for a while.
DebugMsg("My service is sleeping (%lu)...", m_iState);
Sleep(1000);
// Update the current state.
m_iState += m_iIncParam;
}
}		</pre>
　　注意，只要服务不终止，这个函数就不会退出。<appname>当有终止服务的<appname>请求<appname>时，CNTService::m_bIsRunning 标志被置成 FALSE。<appname>如果在服务终止时，你要实现清除操作，那么<appname><appname>你还可以改写 <appname>OnStop 和/或 OnShutdown。<br><br><em>响应控制请求</em><br>　　你可以用任何适合的方式与服务通讯——命名管道，思想交流，便条等等——对于一些简单的请求，用系统函数<appname> ControlService 很容易实现。<appname>CNTService 提供了一个处理器专门用于通过 <appname>ControlService 函数发送的<appname>非标准消息（也就是用户发送的消息）。本文例子用单一消息在注册表中<appname>保存当前服务的状态，以便其它应用程序能看到它。我不建议用这种方法来监控服务，因为它不是最佳方法，这只是比较容易编码实现而已。<appname>ControlService 所能处理的用户消息必须在 <appname>128 到 255 这个范围。我定义了一个常量 <appname>SERVICE_CONTROL_USER，128 作为基值。范围内的用户消息被发送到 <appname>CNTService:: OnUserControl，在例子服务中，处理此消息的细节如下：<br>
<pre>BOOL CMyService::OnUserControl(DWORD dwOpcode)
{
switch (dwOpcode) {
case SERVICE_CONTROL_USER + 0:
// Save the current status in the registry.
SaveStatus();
return TRUE;
default:
break;
}
return FALSE;   // say not handled
}		</pre>
SaveStatus 是一个局部函数，用来在注册表中存储服务状态。<br><br><img src="http://www.vckbase.com/document/image/paragraph.gif"><strong> 调试 Win32 服务</strong><br><br>　　main 函数中包含一个对 <appname><appname><appname><appname><appname><appname><appname><appname><appname>DebugBreak 的调用，当服务第一次被启动时，它会激活系统调试器。你可以监控来自调试器命令窗口中的服务调试信息。你可以在服务中用 <appname><appname><appname><appname><appname><appname><appname><appname><appname>CNTService::DebugMsg 来报告调试期间感兴趣的事件。<br>　　为了调试服务代码，你需要按照<appname><appname><appname> Platform SDK 文档中的要求<appname>安装 系统调试器（<appname><appname><appname><appname><appname><appname><appname><appname><appname>WinDbg）。你也可以用<appname><appname><appname><appname><appname> Visual Studio 自带的调试器调试 Win32 服务。<br>　　有一点很重要，<appname><appname><appname><appname><appname><appname><appname><appname><appname>那就是 当它被服务管理器控制时，你不能终止服务和单步执行，因为服务管理器会让<appname><appname><appname><appname><appname><appname><appname><appname><appname>服务请求 超时并终止服务线程。所以你只能让服务吐出消息，跟踪其过程并在调试器窗口查看它们。<br>　　当服务启动后（例如，从控制面板的&#8220;<appname><appname><appname><appname><appname><appname><appname><appname><appname>服务&#8221;中），调试器将在服务线程的挂起后启动。你需要通过单击&#8220;Go&#8221;按钮或按 F5 让继续运行。然后在调试器中观察服务的运行过程。<br><br>下面是启动和终止服务的调试输出例子：
<pre>Module Load: WinDebug/NTService.exe (symbol loading deferred)
Thread Create: Process=0, Thread=0
Module Load: C:\NT351\system32\NTDLL.DLL (symbol loading deferred)
Module Load: C:\NT351\system32\KERNEL32.DLL (symbol loading deferred)
Module Load: C:\NT351\system32\ADVAPI32.DLL (symbol loading deferred)
Module Load: C:\NT351\system32\RPCRT4.DLL (symbol loading deferred)
Thread Create: Process=0, Thread=1
*** WARNING: symbols checksum is wrong 0x0005830f 0x0005224f for C:\NT351\symbols\dll\NTDLL.DBG
Module Load: C:\NT351\symbols\dll\NTDLL.DBG (symbols loaded)
Thread Terminate: Process=0, Thread=1, Exit Code=0
Hard coded breakpoint hit
Hard coded breakpoint hit
[](130): CNTService::CNTService()
Module Load: C:\NT351\SYSTEM32\RPCLTC1.DLL (symbol loading deferred)
[NT Service Demonstration](130): Calling StartServiceCtrlDispatcher()
Thread Create: Process=0, Thread=2
[NT Service Demonstration](174): Entering CNTService::ServiceMain()
[NT Service Demonstration](174): Entering CNTService::Initialize()
[NT Service Demonstration](174): CNTService::SetStatus(3026680, 2)
[NT Service Demonstration](174): Sleeping...
[NT Service Demonstration](174): CNTService::SetStatus(3026680, 4)
[NT Service Demonstration](174): Entering CNTService::Run()
[NT Service Demonstration](174): Sleeping...
[NT Service Demonstration](174): Sleeping...
[NT Service Demonstration](174): Sleeping...
[NT Service Demonstration](130): CNTService::Handler(1)
[NT Service Demonstration](130): Entering CNTService::Stop()
[NT Service Demonstration](130): CNTService::SetStatus(3026680, 3)
[NT Service Demonstration](130): Leaving CNTService::Stop()
[NT Service Demonstration](130): Updating status (3026680, 3)
[NT Service Demonstration](174): Leaving CNTService::Run()
[NT Service Demonstration](174): Leaving CNTService::Initialize()
[NT Service Demonstration](174): Leaving CNTService::ServiceMain()
[NT Service Demonstration](174): CNTService::SetStatus(3026680, 1)
Thread Terminate: Process=0, Thread=2, Exit Code=0
[NT Service Demonstration](130): Returned from StartServiceCtrlDispatcher()
Module Unload: WinDebug/NTService.exe
Module Unload: C:\NT351\system32\NTDLL.DLL
Module Unload: C:\NT351\system32\KERNEL32.DLL
Module Unload: C:\NT351\system32\ADVAPI32.DLL
Module Unload: C:\NT351\system32\RPCRT4.DLL
Module Unload: C:\NT351\SYSTEM32\RPCLTC1.DLL
Thread Terminate: Process=0, Thread=0, Exit Code=0
Process Terminate: Process=0, Exit Code=0
&gt;</pre>
<p><appname><appname><appname><appname><appname><appname><appname><appname><appname><img src="http://www.vckbase.com/document/image/paragraph.gif"> <strong>总结</strong><br><br>　　也许用 C++ 创建 Win32 服务并不是最理想的，但使用单一的类来派生你自己的服务的确方便了你的服务开发工作。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="COLOR: #008000">PS:手动测试时可能需要&nbsp;SC 命令的协助</p>
<img src ="http://www.cnitblog.com/wufajiaru/aggbug/56323.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/wufajiaru/" target="_blank">巴西木</a> 2009-04-13 16:41 <a href="http://www.cnitblog.com/wufajiaru/archive/2009/04/13/56323.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC解析XML的方法</title><link>http://www.cnitblog.com/wufajiaru/archive/2009/03/13/55393.html</link><dc:creator>巴西木</dc:creator><author>巴西木</author><pubDate>Fri, 13 Mar 2009 07:56:00 GMT</pubDate><guid>http://www.cnitblog.com/wufajiaru/archive/2009/03/13/55393.html</guid><wfw:comment>http://www.cnitblog.com/wufajiaru/comments/55393.html</wfw:comment><comments>http://www.cnitblog.com/wufajiaru/archive/2009/03/13/55393.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/wufajiaru/comments/commentRss/55393.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/wufajiaru/services/trackbacks/55393.html</trackback:ping><description><![CDATA[<br><br>三、MSXML<br>　　<br>&nbsp;&nbsp;&nbsp;&nbsp; 从理论上说，根据XML的格式定义，我们可以自己编写一个XML的语法分析器，但实际上微软已经给我们提供了一个XML语法解析器，即一个叫做 MSXML.DLL的动态链接库，实际上它是一个COM（Component Object Model）对象库，里面封装了进行XML解析时所需要的所 有对象。因为COM是一种以二进制格式出现的和语言无关的可重用对象，所以你可以用任何语言(比如VB，VC，DELPHI，C++ Builder甚至 是脚本语言等等)对它进行调用，在你的应用中实现对XML文档的解析。<br>　　MSXML.DLL所包括的主要COM接口有：<br>　　1. IXMLDOMDocument(Document接口)<br>DOMDocument 对象是XML DOM的基础，你可以利用它所暴露的属性和方法来浏览、查询和修改XML文档的内容和结构。DOMDocument表示了树的顶层节点，它 实现了DOM文档的所有的基本方法，并且提供了额外的成员函数来支持XSL和XSLT。它创建了一个文档对象，所有其他的对象都可以从这个文档对象中得到 和创建。<br>　　2. IXMLDOMNode(Node接口)<br>　　IXMLDOMNode是文档对象模型(DOM)中的基本对象，元素、属性、注释、过程指令和其他的文档组件都可以认为是IXMLDOMNode。事实上，DOMDocument对象本身也是一个IXMLDOMNode对象。<br>　　3. IXMLDOMNodeList<br>　　IXMLDOMNodeList实际上是一个节点(Node)对象的集合，节点的增加、删除和变化都可以在集合中立刻反映出来，可以通过"for.循环 "结构来遍历所有的节点。<br>　　4. IXMLDOMParseError<br>　　IXMLDOMParseError接口用来返回在解析过程中所出现的详细的信息，包括错误号、行号、字符位置和文本描述。<br>　 　在具体应用时可以用DOMDocument的Load方法来装载XML文档，用IXMLDOMNode 的selectNodes（查询的结果有多个， 得到存放搜索结果的链表）或selectSingleNode（查询的结果有一个，在有多个的情况下返回找到的第一个节点）方法进行查询，用 createNode和appendChild方法来创建节点和追加节点，用IXMLDOMElement的setAttribute和 getAttribute方法来设置和获得节点的属性。
<p>&#160;</p>
<p><br><br><img src="http://bbs.xml.org.cn/images/files/jpg.gif" border=0>此主题相关图片如下：<br><a class=contentlink href="http://bbs.xml.org.cn/uploadfile/20051025222278948.jpg" target=_blank><img src="http://bbs.xml.org.cn/uploadfile/20051025222278948.jpg" border=0 dypop="按此在新窗口浏览图片"></a></p>
<p>&#160;</p>
<p>四、编程举例</p>
<p>&#160;</p>
<p>1、目标文档：&nbsp;&nbsp;</p>
<p>&lt;book id="bk101"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;author&gt;lizlex&lt;/author&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;XML Developer's Guide&lt;/title&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/book&gt;</p>
<p>2、步骤：</p>
<p>(1)在StdAfx.h中引入动态链接库 MSXML.DLL(C:\windows\system32\msxml4.dll)<br>#import &lt;msxml4.dll&gt;</p>
<p>(2)界面设计：<br>分别放入三个Text，用于输入数据，与显示文档内容用，并添加关联的成员变量m_strId,m_strAuthor, m_strTitle；并添加确定按钮：</p>
<p>(3)产生文档的程序片断<br>void CXmlparseDlg::OnButtonGenerate() <br>{<br>UpdateData();</p>
<p>MSXML2::IXMLDOMDocumentPtr pDoc; <br>MSXML2::IXMLDOMElementPtr&nbsp;&nbsp; xmlRoot ;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //创建DOMDocument对象 <br>HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40)); <br>if(!SUCCEEDED(hr)) <br>{&nbsp;&nbsp;<br>&nbsp;&nbsp; MessageBox("无法创建DOMDocument对象，请检查是否安装了MS XML Parser 运行库!"); <br>&nbsp;&nbsp; return ;<br>} <br><br>//根节点的名称为Book<br>//创建元素并添加到文档中<br>xmlRoot=pDoc-&gt;createElement((_bstr_t)"Book");<br><br>//设置属性<br>xmlRoot-&gt;setAttribute("id",(const char *)m_strId);<br>pDoc-&gt;appendChild(xmlRoot);<br>MSXML2::IXMLDOMElementPtr pNode;</p>
<p>//添加&#8220;author&#8221;元素<br>pNode=pDoc-&gt;createElement((_bstr_t)"Author");<br>pNode-&gt;Puttext((_bstr_t)(const char *)m_strAuthor);<br>xmlRoot-&gt;appendChild(pNode);<br><br>//添加&#8220;Title&#8221;元素<br>pNode=pDoc-&gt;createElement("Title");<br>pNode-&gt;Puttext((const char *)m_strTitle);<br>xmlRoot-&gt;appendChild(pNode);<br><br>//保存到文件 <br>//如果不存在就建立,存在就覆盖 <br>pDoc-&gt;save("d:\\he.xml");</p>
<p>}</p>
<p>(4)读取XML文档的程序片断<br>void CXmlparseDlg::OnButtonLoad() <br>{<br>MSXML2::IXMLDOMDocumentPtr pDoc;<br>HRESULT hr;<br>hr=pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40));<br>if(FAILED(hr))<br>{&nbsp;&nbsp;<br>&nbsp;&nbsp; MessageBox("无法创建DOMDocument对象，请检查是否安装了MS XML Parser 运行库!"); <br>&nbsp;&nbsp; return ;<br>} <br><br>//加载文件 <br>pDoc-&gt;load("d:\\he.xml"); <br><br>MSXML2::IXMLDOMNodePtr&nbsp;&nbsp; pNode;<br><br>//在树中查找名为Book的节点,"//"表示在任意一层查找 <br>pNode=pDoc-&gt;selectSingleNode("//Book");</p>
<p>MSXML2::DOMNodeType nodeType; <br><br>//得到节点类型 <br>&nbsp;&nbsp;&nbsp;&nbsp; pNode-&gt;get_nodeType(&amp;nodeType); <br><br>//节点名称 <br>CString strName;<br><br>strName=(char *)pNode-&gt;GetnodeName();<br><br>//节点属性,放在链表中 <br>MSXML2::IXMLDOMNamedNodeMapPtr pAttrMap=NULL;<br>MSXML2::IXMLDOMNodePtr&nbsp;&nbsp;&nbsp; pAttrItem;<br>_variant_t variant<em>value</em>;<br>pNode-&gt;get_attributes(&amp;pAttrMap);<br><br>long count;<br>count=pAttrMap-&gt;get_length(&amp;count);<br><br>pAttrMap-&gt;get_item(0,&amp;pAttrItem);<br>//取得节点的值<br>pAttrItem-&gt;get_nodeTyped<em>value</em>(&amp;variant<em>value</em>);<br>m_strId=(char *)(_bstr_t)variant<em>value</em>;<br><br>UpdateData(FALSE);<br><br>}<br><br><img src="http://bbs.xml.org.cn/images/files/jpg.gif" border=0>此主题相关图片如下：<br><a class=contentlink href="http://bbs.xml.org.cn/uploadfile/2005102522505126021.jpg" target=_blank><img src="http://bbs.xml.org.cn/uploadfile/2005102522505126021.jpg" border=0 dypop="按此在新窗口浏览图片"></a></p>
<img src ="http://www.cnitblog.com/wufajiaru/aggbug/55393.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/wufajiaru/" target="_blank">巴西木</a> 2009-03-13 15:56 <a href="http://www.cnitblog.com/wufajiaru/archive/2009/03/13/55393.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>