﻿<?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++博客-hello world</title><link>http://www.cppblog.com/heavyz/</link><description>Programmer Tue</description><language>zh-cn</language><lastBuildDate>Thu, 23 Apr 2026 10:15:22 GMT</lastBuildDate><pubDate>Thu, 23 Apr 2026 10:15:22 GMT</pubDate><ttl>60</ttl><item><title>令人迷惑的Bridge模式</title><link>http://www.cppblog.com/heavyz/archive/2006/07/31/10744.html</link><dc:creator>ZHENG Zhong</dc:creator><author>ZHENG Zhong</author><pubDate>Mon, 31 Jul 2006 13:20:00 GMT</pubDate><guid>http://www.cppblog.com/heavyz/archive/2006/07/31/10744.html</guid><wfw:comment>http://www.cppblog.com/heavyz/comments/10744.html</wfw:comment><comments>http://www.cppblog.com/heavyz/archive/2006/07/31/10744.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heavyz/comments/commentRss/10744.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heavyz/services/trackbacks/10744.html</trackback:ping><description><![CDATA[
		<b>问题：</b>
		<br />
		<br />一开始，H公司的程序员选择了MSXML作为XML解析工具。后来终于发现了MSXML的愚蠢(注：本文不讨论为什么MSXML是愚蠢的)，于是决定把MSXML换成libxml2。由于已经有大量的代码是直接基于MSXML开发的，因此这样的移植工作相当的劳民伤财。为了防止以后再发生这样的悲剧，H公司决定为XML解析器提供一个wrapper层，该层抽象出了一个与具体解析器无关的抽象XML Processing API，程序员使用这个API来完成XML解析，而不必关心底层的解析器到底是使用了MSXML还是libxml2，或者是Xerces-C++。这样，一旦以后需要更换XML解析器，比如从libxml2换成expat，只需要使用expat重新实现一下XML wrapper API即可，客户程序员不用在为移植他们的程序而伤脑筋，他们甚至不用再重新编译他们的代码。<br /><br /><b>目标：</b><br /><ol><li>我希望解耦合XML Processing API和具体的实现。</li><li>我希望向客户程序员完全隐藏抽象接口的实现细节。</li><li>我希望对抽象接口的实现部分的修改不会对客户程序员有任何的影响，即客户的代码无须重新编译。</li></ol>从目标来看，GoF的Bridge模式似乎是一个不二选择。<br /><br /><br /><br /><br /><br /><img src ="http://www.cppblog.com/heavyz/aggbug/10744.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heavyz/" target="_blank">ZHENG Zhong</a> 2006-07-31 21:20 <a href="http://www.cppblog.com/heavyz/archive/2006/07/31/10744.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SDL Programming</title><link>http://www.cppblog.com/heavyz/archive/2006/07/31/10738.html</link><dc:creator>ZHENG Zhong</dc:creator><author>ZHENG Zhong</author><pubDate>Mon, 31 Jul 2006 11:02:00 GMT</pubDate><guid>http://www.cppblog.com/heavyz/archive/2006/07/31/10738.html</guid><wfw:comment>http://www.cppblog.com/heavyz/comments/10738.html</wfw:comment><comments>http://www.cppblog.com/heavyz/archive/2006/07/31/10738.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/heavyz/comments/commentRss/10738.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heavyz/services/trackbacks/10738.html</trackback:ping><description><![CDATA[First SDL program:<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><font face="Courier New"><span style="color: rgb(0, 128, 128);">  1</span> <span style="color: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">  2</span> <span style="color: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">iostream</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">  3</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">  4</span> <span style="color: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">SDL</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">SDL.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">  5</span> <span style="color: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">SDL</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">SDL_image.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">  6</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">  7</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">#define</span><span style="color: rgb(0, 0, 0);"> nullptr 0</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">  8</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">  9</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> Attributes of the screen.</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 10</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> SCREEN_WIDTH </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">640</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 11</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> SCREEN_HEIGHT </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">480</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 12</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> SCREEN_BPP </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">32</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 13</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 14</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> Surfaces that will be used.</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 15</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">SDL_Surface</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> message </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> nullptr;<br /></span><span style="color: rgb(0, 128, 128);"> 16</span> <span style="color: rgb(0, 0, 0);">SDL_Surface</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> background </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> nullptr;<br /></span><span style="color: rgb(0, 128, 128);"> 17</span> <span style="color: rgb(0, 0, 0);">SDL_Surface</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> screen </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> nullptr;<br /></span><span style="color: rgb(0, 128, 128);"> 18</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 19</span> <span style="color: rgb(0, 0, 0);">SDL_Surface</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> loadImage(</span><span style="color: rgb(0, 0, 255);">const</span><span style="color: rgb(0, 0, 0);"> std::</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);"> fileName) {<br /></span><span style="color: rgb(0, 128, 128);"> 20</span> <span style="color: rgb(0, 0, 0);">    SDL_Surface</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> loadedImage </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> IMG_Load(fileName.c_str());<br /></span><span style="color: rgb(0, 128, 128);"> 21</span> <span style="color: rgb(0, 0, 0);">    SDL_Surface</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> optimizedImage </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> nullptr;<br /></span><span style="color: rgb(0, 128, 128);"> 22</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (loadedImage </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> nullptr) {<br /></span><span style="color: rgb(0, 128, 128);"> 23</span> <span style="color: rgb(0, 0, 0);">        optimizedImage </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> SDL_DisplayFormat(loadedImage);<br /></span><span style="color: rgb(0, 128, 128);"> 24</span> <span style="color: rgb(0, 0, 0);">        SDL_FreeSurface(loadedImage);<br /></span><span style="color: rgb(0, 128, 128);"> 25</span> <span style="color: rgb(0, 0, 0);">        loadedImage </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> nullptr;<br /></span><span style="color: rgb(0, 128, 128);"> 26</span> <span style="color: rgb(0, 0, 0);">    } </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> {<br /></span><span style="color: rgb(0, 128, 128);"> 27</span> <span style="color: rgb(0, 0, 0);">        std::cerr </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Error loading </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> fileName </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">: </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> IMG_GetError() </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 28</span> <span style="color: rgb(0, 0, 0);">    }<br /></span><span style="color: rgb(0, 128, 128);"> 29</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> optimizedImage;<br /></span><span style="color: rgb(0, 128, 128);"> 30</span> <span style="color: rgb(0, 0, 0);">}<br /></span><span style="color: rgb(0, 128, 128);"> 31</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 32</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> applySurface(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> x, </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> y, SDL_Surface</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> source, SDL_Surface</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> destination) {<br /></span><span style="color: rgb(0, 128, 128);"> 33</span> <span style="color: rgb(0, 0, 0);">    SDL_Rect offset;<br /></span><span style="color: rgb(0, 128, 128);"> 34</span> <span style="color: rgb(0, 0, 0);">    offset.x </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> x;<br /></span><span style="color: rgb(0, 128, 128);"> 35</span> <span style="color: rgb(0, 0, 0);">    offset.y </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> y;<br /></span><span style="color: rgb(0, 128, 128);"> 36</span> <span style="color: rgb(0, 0, 0);">    SDL_BlitSurface(source, nullptr, destination, </span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">offset);<br /></span><span style="color: rgb(0, 128, 128);"> 37</span> <span style="color: rgb(0, 0, 0);">}<br /></span><span style="color: rgb(0, 128, 128);"> 38</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 39</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> main(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> argc, </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);"> argv[]) {<br /></span><span style="color: rgb(0, 128, 128);"> 40</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (SDL_Init(SDL_INIT_EVERYTHING) </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">) {<br /></span><span style="color: rgb(0, 128, 128);"> 41</span> <span style="color: rgb(0, 0, 0);">        std::cerr </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Failed to initialize SDL system.</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 42</span> <span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 43</span> <span style="color: rgb(0, 0, 0);">    }<br /></span><span style="color: rgb(0, 128, 128);"> 44</span> <span style="color: rgb(0, 0, 0);">    screen </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);<br /></span><span style="color: rgb(0, 128, 128);"> 45</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (screen </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> nullptr) {<br /></span><span style="color: rgb(0, 128, 128);"> 46</span> <span style="color: rgb(0, 0, 0);">        std::cerr </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Failed to set video mode.</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 47</span> <span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 48</span> <span style="color: rgb(0, 0, 0);">    }<br /></span><span style="color: rgb(0, 128, 128);"> 49</span> <span style="color: rgb(0, 0, 0);">    SDL_WM_SetCaption(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Hello World</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, nullptr);<br /></span><span style="color: rgb(0, 128, 128);"> 50</span> <span style="color: rgb(0, 0, 0);">    message </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> loadImage(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">helloworld.jpg</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);"> 51</span> <span style="color: rgb(0, 0, 0);">    background </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> loadImage(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">background.gif</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);"> 52</span> <span style="color: rgb(0, 0, 0);">    applySurface(</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">, background, screen);<br /></span><span style="color: rgb(0, 128, 128);"> 53</span> <span style="color: rgb(0, 0, 0);">    applySurface(</span><span style="color: rgb(0, 0, 0);">180</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">140</span><span style="color: rgb(0, 0, 0);">, message, screen);<br /></span><span style="color: rgb(0, 128, 128);"> 54</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (SDL_Flip(screen) </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">) {<br /></span><span style="color: rgb(0, 128, 128);"> 55</span> <span style="color: rgb(0, 0, 0);">        std::cerr </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Failed to flip screen.</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 56</span> <span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 57</span> <span style="color: rgb(0, 0, 0);">    }<br /></span><span style="color: rgb(0, 128, 128);"> 58</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 59</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);">*<br /></span><span style="color: rgb(0, 128, 128);"> 60</span> <span style="color: rgb(0, 128, 0);">    typedef union SDL_Event {<br /></span><span style="color: rgb(0, 128, 128);"> 61</span> <span style="color: rgb(0, 128, 0);">        Uint8 type;<br /></span><span style="color: rgb(0, 128, 128);"> 62</span> <span style="color: rgb(0, 128, 0);">        SDL_ActiveEvent active;<br /></span><span style="color: rgb(0, 128, 128);"> 63</span> <span style="color: rgb(0, 128, 0);">        SDL_KeyboardEvent key;<br /></span><span style="color: rgb(0, 128, 128);"> 64</span> <span style="color: rgb(0, 128, 0);">        SDL_MouseMotionEvent motion;<br /></span><span style="color: rgb(0, 128, 128);"> 65</span> <span style="color: rgb(0, 128, 0);">        SDL_MouseButtonEvent button;<br /></span><span style="color: rgb(0, 128, 128);"> 66</span> <span style="color: rgb(0, 128, 0);">        SDL_JoyAxisEvent jaxis;<br /></span><span style="color: rgb(0, 128, 128);"> 67</span> <span style="color: rgb(0, 128, 0);">        SDL_JoyBallEvent jball;<br /></span><span style="color: rgb(0, 128, 128);"> 68</span> <span style="color: rgb(0, 128, 0);">        SDL_JoyHatEvent jhat;<br /></span><span style="color: rgb(0, 128, 128);"> 69</span> <span style="color: rgb(0, 128, 0);">        SDL_JoyButtonEvent jbutton;<br /></span><span style="color: rgb(0, 128, 128);"> 70</span> <span style="color: rgb(0, 128, 0);">        SDL_ResizeEvent resize;<br /></span><span style="color: rgb(0, 128, 128);"> 71</span> <span style="color: rgb(0, 128, 0);">        SDL_ExposeEvent expose;<br /></span><span style="color: rgb(0, 128, 128);"> 72</span> <span style="color: rgb(0, 128, 0);">        SDL_QuitEvent quit;<br /></span><span style="color: rgb(0, 128, 128);"> 73</span> <span style="color: rgb(0, 128, 0);">        SDL_UserEvent user;<br /></span><span style="color: rgb(0, 128, 128);"> 74</span> <span style="color: rgb(0, 128, 0);">        SDL_SysWMEvent syswm;<br /></span><span style="color: rgb(0, 128, 128);"> 75</span> <span style="color: rgb(0, 128, 0);">    } SDL_Event;<br /></span><span style="color: rgb(0, 128, 128);"> 76</span> <span style="color: rgb(0, 128, 0);">    *</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 77</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">bool</span><span style="color: rgb(0, 0, 0);"> quit </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">false</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 78</span> <span style="color: rgb(0, 0, 0);">    SDL_Event </span><span style="color: rgb(0, 0, 255);">event</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 79</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">quit) {<br /></span><span style="color: rgb(0, 128, 128);"> 80</span> <span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> (SDL_PollEvent(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 255);">event</span><span style="color: rgb(0, 0, 0);">)) {<br /></span><span style="color: rgb(0, 128, 128);"> 81</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">switch</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">event</span><span style="color: rgb(0, 0, 0);">.type) {<br /></span><span style="color: rgb(0, 128, 128);"> 82</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">case</span><span style="color: rgb(0, 0, 0);"> SDL_QUIT:<br /></span><span style="color: rgb(0, 128, 128);"> 83</span> <span style="color: rgb(0, 0, 0);">                std::cerr </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">User requested to quit!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 84</span> <span style="color: rgb(0, 0, 0);">                quit </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 85</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 86</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">case</span><span style="color: rgb(0, 0, 0);"> SDL_ACTIVEEVENT:<br /></span><span style="color: rgb(0, 128, 128);"> 87</span> <span style="color: rgb(0, 0, 0);">                std::cout </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Active event!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 88</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 89</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">case</span><span style="color: rgb(0, 0, 0);"> SDL_KEYUP:<br /></span><span style="color: rgb(0, 128, 128);"> 90</span> <span style="color: rgb(0, 0, 0);">                std::cout </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Key up event!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 91</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 92</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">case</span><span style="color: rgb(0, 0, 0);"> SDL_KEYDOWN:<br /></span><span style="color: rgb(0, 128, 128);"> 93</span> <span style="color: rgb(0, 0, 0);">                std::cout </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Key down event!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 94</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 95</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">case</span><span style="color: rgb(0, 0, 0);"> SDL_MOUSEMOTION:<br /></span><span style="color: rgb(0, 128, 128);"> 96</span> <span style="color: rgb(0, 0, 0);">                std::cout </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Mouse motion event!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);"> 97</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 98</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">case</span><span style="color: rgb(0, 0, 0);"> SDL_MOUSEBUTTONUP:<br /></span><span style="color: rgb(0, 128, 128);"> 99</span> <span style="color: rgb(0, 0, 0);">                std::cout </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Mouse button up event!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);">100</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">101</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">case</span><span style="color: rgb(0, 0, 0);"> SDL_MOUSEBUTTONDOWN:<br /></span><span style="color: rgb(0, 128, 128);">102</span> <span style="color: rgb(0, 0, 0);">                std::cout </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Mouse button down event!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);">103</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">104</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">case</span><span style="color: rgb(0, 0, 0);"> SDL_SYSWMEVENT:<br /></span><span style="color: rgb(0, 128, 128);">105</span> <span style="color: rgb(0, 0, 0);">                std::cout </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">System specific event!</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);">106</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">107</span> <span style="color: rgb(0, 0, 0);">            </span><span style="color: rgb(0, 0, 255);">default</span><span style="color: rgb(0, 0, 0);">:<br /></span><span style="color: rgb(0, 128, 128);">108</span> <span style="color: rgb(0, 0, 0);">                std::cout </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Other event: </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">event</span><span style="color: rgb(0, 0, 0);">.type </span><span style="color: rgb(0, 0, 0);">&lt;&lt;</span><span style="color: rgb(0, 0, 0);"> std::endl;<br /></span><span style="color: rgb(0, 128, 128);">109</span> <span style="color: rgb(0, 0, 0);">                </span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">110</span> <span style="color: rgb(0, 0, 0);">            }<br /></span><span style="color: rgb(0, 128, 128);">111</span> <span style="color: rgb(0, 0, 0);">        }<br /></span><span style="color: rgb(0, 128, 128);">112</span> <span style="color: rgb(0, 0, 0);">    }<br /></span><span style="color: rgb(0, 128, 128);">113</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">114</span> <span style="color: rgb(0, 0, 0);">    SDL_FreeSurface(message);<br /></span><span style="color: rgb(0, 128, 128);">115</span> <span style="color: rgb(0, 0, 0);">    SDL_FreeSurface(background);<br /></span><span style="color: rgb(0, 128, 128);">116</span> <span style="color: rgb(0, 0, 0);">    SDL_Quit();<br /></span><span style="color: rgb(0, 128, 128);">117</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">118</span> <span style="color: rgb(0, 0, 0);">}</span></font></div><br />Configurations:<br /><br />1. Download SDL-devel-1.2011 for win32: http://www.libsdl.org<br />2. Download SDL_image-devel-1.2.5 for win32: http://www.libsdl.org/projects/SDL_image/<br />3. Visual Studio.NET 2003: C/C++, Code Generation, Runtime Library, select: Multi-Threaded (Debug) DLL (/MD or /MDd)<br /><br /><img src ="http://www.cppblog.com/heavyz/aggbug/10738.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heavyz/" target="_blank">ZHENG Zhong</a> 2006-07-31 19:02 <a href="http://www.cppblog.com/heavyz/archive/2006/07/31/10738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转] 用VC进行COM编程所必须掌握的理论知识</title><link>http://www.cppblog.com/heavyz/archive/2006/07/12/9777.html</link><dc:creator>ZHENG Zhong</dc:creator><author>ZHENG Zhong</author><pubDate>Wed, 12 Jul 2006 11:56:00 GMT</pubDate><guid>http://www.cppblog.com/heavyz/archive/2006/07/12/9777.html</guid><wfw:comment>http://www.cppblog.com/heavyz/comments/9777.html</wfw:comment><comments>http://www.cppblog.com/heavyz/archive/2006/07/12/9777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heavyz/comments/commentRss/9777.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heavyz/services/trackbacks/9777.html</trackback:ping><description><![CDATA[这篇文章是给初学者看的，尽量写得比较通俗易懂，并且尽量避免编程细节。完全是根据我自己的学习体会写的，其中若有技术上的错误之处，请大家多多指正。 
<br /><br />一、为什么要用COM 
<br /><br />软件工程发展到今天，从一开始的结构化编程，到面向对象编程，再到现在的COM编程，目标只有一个，就是希望软件能象积方块一样是累起来的，
是组装起来的，而不是一点点编出来的。结构化编程是函数块的形式，通过把一个软件划分成许多模块，每个模块完成各自不同的功能，尽量做到高内聚低藕合，这
已经是一个很好的开始，我们可以把不同的模块分给不同的人去做，然后合到一块，这已经有了组装的概念了。软件工程的核心就是要模块化，最理想的情况就是
100%内聚0%藕合。整个软件的发展也都是朝着这个方向走的。结构化编程方式只是一个开始。下一步就出现了面向对象编程，它相对于面向功能的结构化方式
是一个巨大的进步。我们知道整个自然界都是由各种各样不同的事物组成的，事物之间存在着复杂的千丝万缕的关系，而正是靠着事物之间的联系、交互作用，我们
的世界才是有生命力的才是活动的。我们可以认为在自然界中事物做为一个概念，它是稳定的不变的，而事物之间的联系是多变的、运动的。事物应该是这个世界的
本质所在。面向对象的着眼点就是事物，就是这种稳定的概念。每个事物都有其固有的属性，都有其固有的行为，这些都是事物本身所固有的东西，而面向对象的方
法就是描述出这种稳定的东西。而面向功能的模块化方法它的着眼点是事物之间的联系，它眼中看不到事物的概念它只注重功能，我们平常在划分模块的时侯有没有
想过这个函数与哪些对象有关呢？很少有人这么想，一个函数它实现一种功能，这个功能必定与某些事物想联系，我们没有去掌握事物本身而只考虑事物之间是怎么
相互作用而完成一个功能的。说白了，这叫本末倒置，也叫急功近利，因为不是我们智慧不够，只是因为我们没有多想一步。面向功能的结构化方法因为它注意的只
是事物之间的联系，而联系是多变的，事物本身可能不会发生大的变化，而联系则是很有可能发生改变的，联系一变，那就是另一个世界了，那就是另一种功能了。
如果我们用面向对象的方法，我们就可以以不变应万变，只要事先把事物用类描述好，我们要改变的只是把这些类联系起来的方法，只是重新使用我们的类库，而面
向过程的方法因为它构造的是一个不稳定的世界，所以一点小小的变化也可能导致整个系统都要改变。然而面向对象方法仍然有问题，问题在于重用的方法。搭积木
式的软件构造方法的基础是有许许多多各种各样的可重用的部件、模块。我们首先想到的是类库，因为我们用面向对象的方法产生的直接结果就是许多的类。但类库
的重用是基于源码的方式，这是它的重大缺陷。首先它限制了编程语言，你的类库总是用一种语言写的吧，那你就不能拿到别的语言里用了。其次你每次都必须重新
编译，只有编译了才能与你自己的代码结合在一起生成可执行文件。在开发时这倒没什么，关键在于开发完成后，你的EXE都已经生成好了，如果这时侯你的类库
提供厂商告诉你他们又做好了一个新的类库，功能更强大速度更快，而你为之心动又想把这新版的类库用到你自己的程序中，那你就必须重新编译、重新调试！这离
我们理想的积木式软件构造方法还有一定差距，在我们的设想里希望把一个模块拿出来再换一个新的模块是非常方便的事，可是现在不但要重新编译，还要冒着很大
的风险，因为你可能要重新改变你自己的代码。另一种重用方式很自然地就想到了是DLL的方式。Windows里到处是DLL，它是Windows
的基础，但DLL也有它自己的缺点。总结一下它至少有四点不足。(1)函数重名问题。DLL里是一个一个的函数，我们通过函数名来调用函数，那如果两个
DLL里有重名的函数怎么办？(2)各编译器对C＋＋函数的名称修饰不兼容问题。对于C＋＋函数，编译器要根据函数的参数信息为它生成修饰名，DLL库里
存的就是这个修饰名，但是不同的编译器产生修饰的方法不一样，所以你在VC 里编写的DLL在BC里就可以用不了。不过也可以用extern
"C";来强调使用标准的C函数特性，关闭修饰功能，但这样也丧失了C＋＋的重载多态性功能。(3)路径问题。放在自己的目录下面，别人的程序就找不到，
放在系统目录下，就可能有重名的问题。而真正的组件应该可以放在任何地方甚至可以不在本机，用户根本不需考虑这个问题。(4)DLL与EXE的依赖问题。
我们一般都是用隐式连接的方式，就是编程的时侯指明用什么DLL，这种方式很简单，它在编译时就把EXE与DLL绑在一起了。如果DLL发行了一个新版
本，我们很有必要重新链接一次，因为DLL里面函数的地址可能已经发生了改变。DLL的缺点就是COM的优点。首先我们要先把握住一点，COM和DLL一
样都是基于二进制的代码重用，所以它不存在类库重用时的问题。另一个关键点是，COM本身也是DLL，既使是ActiveX控件.ocx它实际上也是
DLL，所以说DLL在还是有重用上有很大的优势，只不过我们通过制订复杂的COM协议，通COM本身的机制改变了重用的方法，以一种新的方法来利用
DLL，来克服DLL本身所固有的缺陷，从而实现更高一级的重用方法。COM没有重名问题，因为根本不是通过函数名来调用函数，而是通过虚函数表，自然也
不会有函数名修饰的问题。路径问题也不复存在，因为是通过查注册表来找组件的，放在什么地方都可以，即使在别的机器上也可以。也不用考虑和EXE的依赖关
系了，它们二者之间是松散的结合在一起，可以轻松的换上组件的一个新版本，而应用程序混然不觉。 <br /><br />二、用VC进行COM编程，必须要掌握哪些COM理论知识 
<br /><br />我见过很多人学COM，看完一本书后觉得对COM的原理比较了解了，COM也不过如此，可是就是不知道该怎么编程序，我自己也有这种情况，我
也是经历了这样的阶段走过来的。要学COM的基本原理，我推荐的书是《COM技术内幕》。但仅看这样的书是远远不够的，我们最终的目的是要学会怎么用
COM去编程序，而不是拼命的研究COM本身的机制。所以我个人觉得对COM的基本原理不需要花大量的时间去追根问底，没有必要，是吃力不讨好的事。其实
我们只需要掌握几个关键概念就够了。这里我列出了一些我自己认为是用VC编程所必需掌握的几个关键概念。(这里所说的均是用C++语言条件下的COM编程
方式) <br /><br />(1) COM组件实际上是一个C++类，而接口都是纯虚类。组件从接口派生而来。我们可以简单的用纯粹的C++的语法形式来描述COM是个什么东西： 
<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><font face="Courier New"><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> IObject {<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">:<br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">virtual</span><span style="color: rgb(0, 0, 0);"> Function1(..) </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">virtual</span><span style="color: rgb(0, 0, 0);"> Function2(..) </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">    ..<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">};<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> MyObject : </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> IObject {<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">:<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">virtual</span><span style="color: rgb(0, 0, 0);"> Function1(..) {..}<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">virtual</span><span style="color: rgb(0, 0, 0);"> Function2(..) {..}<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">    ..<br /></span><span style="color: rgb(0, 128, 128);">13</span> </font><span style="color: rgb(0, 0, 0);"><font face="Courier New">};</font><br /></span><span style="color: rgb(0, 128, 128);"></span><span style="color: rgb(0, 0, 0);"></span></div><br />看清楚了吗？IObject就是我们常说的接口，MyObject就是所谓的COM组件。切记切记接口都是纯虚类，它所包含的函数都是纯虚函
数，而且它没有成员变量。而COM组件就是从这些纯虚类继承下来的派生类，它实现了这些虚函数，仅此而已。从上面也可以看出，COM组件是以
C++为基础的，特别重要的是虚函数和多态性的概念，COM中所有函数都是虚函数，都必须通过虚函数表VTable来调用，这一点是无比重要的，必需时刻
牢记在心。
<br /><br />(2) COM组件有三个最基本的接口类，分别是IUnknown、IClassFactory、IDispatch。 
<br /><br />COM规范规定任何组件、任何接口都必须从IUnknown继承，IUnknown包含三个函数，分别是
QueryInterface、AddRef、Release。这三个函数是无比重要的，而且它们的排列顺序也是不可改变的。
QueryInterface用于查询组件实现的其它接口，说白了也就是看看这个组件的父类中还有哪些接口类，AddRef用于增加引用计数，
Release用于减少引用计数。引用计数也是COM中的一个非常重要的概念。大体上简单的说来可以这么理解，COM组件是个DLL，当客户程序要用它时
就要把它装到内存里。另一方面，一个组件也不是只给你一个人用的，可能会有很多个程序同时都要用到它。但实际上DLL只装载了一次，即内存中只有一个
COM组件，那COM组件由谁来释放？由客户程序吗？不可能，因为如果你释放了组件，那别人怎么用，所以只能由COM组件自己来负责。所以出现了引用计数
的概念，COM维持一个计数，记录当前有多少人在用它，每多一次调用计数就加一，少一个客户用它就减一，当最后一个客户释放它的时侯，COM知道已经没有
人用它了，它的使用已经结束了，那它就把它自己给释放了。引用计数是COM编程里非常容易出错的一个地方，但所幸VC的各种各样的类库里已经基本上把
AddRef的调用给隐含了，在我的印象里，我编程的时侯还从来没有调用过AddRef，我们只需在适当的时侯调用Release。至少有两个时侯要记住
调用Release，第一个是调用了 QueryInterface以后，第二个是调用了任何得到一个接口的指针的函数以后，记住多查MSDN
以确定某个函数内部是否调用了AddRef，如果是的话那调用Release的责任就要归你了。
IUnknown的这三个函数的实现非常规范但也非常烦琐，容易出错，所幸的事我们可能永远也不需要自己来实现它们。 <br /><br />IClassFactory的作用是创建COM组件。我们已经知道COM组件实际上就是一个类，那我们平常是怎么实例化一个类对象的？是用
‘new’命令!很简单吧，COM组件也一样如此。但是谁来new它呢？不可能是客户程序，因为客户程序不可能知道组件的类名字，如果客户知道组件的类名
字那组件的可重用性就要打个大大的折扣了，事实上客户程序只不过知道一个代表着组件的128位的数字串而已，这个等会再介绍。所以客户无法自己创建组件，
而且考虑一下，如果组件是在远程的机器上，你还能new出一个对象吗？所以创建组件的责任交给了一个单独的对象，这个对象就是类厂。每个组件都必须有一个
与之相关的类厂，这个类厂知道怎么样创建组件，当客户请求一个组件对象的实例时，实际上这个请求交给了类厂，由类厂创建组件实例，然后把实例指针交给客户
程序。这个过程在跨进程及远程创建组件时特别有用，因为这时就不是一个简单的new操作就可以的了，它必须要经过调度，而这些复杂的操作都交给类厂对象去
做了。IClassFactory最重要的一个函数就是CreateInstance，顾名思议就是创建组件实例，一般情况下我们不会直接调用它，API
函数都为我们封装好它了，只有某些特殊情况下才会由我们自己来调用它，这也是VC编写COM组件的好处，使我们有了更多的控制机会，而VB给我们这样的机
会则是太少太少了。 <br /><br />IDispatch叫做调度接口。它的作用何在呢？这个世上除了C++还有很多别的语言，比如VB、
VJ、VBScript、JavaScript等等。可以这么说，如果这世上没有这么多乱七八糟的语言，那就不会有IDispatch。:-)
我们知道COM组件是C++类，是靠虚函数表来调用函数的，对于VC来说毫无问题，这本来就是针对C++而设计的，以前VB不行，现在VB也可以用指针
了，也可以通过VTable来调用函数了，VJ也可以，但还是有些语言不行，那就是脚本语言，典型的如
VBScript、JavaScript。不行的原因在于它们并不支持指针，连指针都不能用还怎么用多态性啊，还怎么调这些虚函数啊。唉，没办法，也不能
置这些脚本语言于不顾吧，现在网页上用的都是这些脚本语言，而分布式应用也是COM组件的一个主要市场，它不得不被这些脚本语言所调用，既然虚函数表的方
式行不通，我们只能另寻他法了。时势造英雄，IDispatch应运而生。:-)
调度接口把每一个函数每一个属性都编上号，客户程序要调用这些函数属性的时侯就把这些编号传给IDispatch接口就行了，IDispatch再根据这
些编号调用相应的函数，仅此而已。当然实际的过程远比这复杂，仅给一个编号就能让别人知道怎么调用一个函数那不是天方夜潭吗，你总得让别人知道你要调用的
函数要带什么参数，参数类型什么以及返回什么东西吧，而要以一种统一的方式来处理这些问题是件很头疼的事。IDispatch接口的主要函数是
Invoke，客户程序都调用它，然后Invoke再调用相应的函数，如果看一看MS的类库里实现
Invoke的代码就会惊叹它实现的复杂了，因为你必须考虑各种参数类型的情况，所幸我们不需要自己来做这件事，而且可能永远也没这样的机会。:-) <br /><br />(3) dispinterface接口、Dual接口以及Custom接口 
<br /><br />这一小节放在这里似乎不太合适，因为这是在ATL编程时用到的术语。我在这里主要是想谈一下自动化接口的好处及缺点，用这三个术语来解释可能
会更好一些，而且以后迟早会遇上它们，我将以一种通俗的方式来解释它们，可能并非那么精确，就好象用伪代码来描述算法一样。-:) <br /><br />所谓的自动化接口就是用IDispatch实现的接口。我们已经讲解过IDispatch的作用了，它的好处就是脚本语言象
VBScript、
JavaScript也能用COM组件了，从而基本上做到了与语言无关它的缺点主要有两个，第一个就是速度慢效率低。这是显而易见的，通过虚函数表一下子
就可以调用函数了，而通过Invoke则等于中间转了道手续，尤其是需要把函数参数转换成一种规范的格式才去调用函数，耽误了很多时间。所以一般若非是迫
不得已我们都想用VTable的方式调用函数以获得高效率。第二个缺点就是只能使用规定好的所谓的自动化数据类型。如果不用IDispatch我们可以想
用什么数据类型就用什么类型，VC会自动给我们生成相应的调度代码。而用自动化接口就不行了，因为Invoke的实现代码是VC事先写好的，而它不能事先
预料到我们要用到的所有类型，它只能根据一些常用的数据类型来写它的处理代码，而且它也要考虑不同语言之间的数据类型转换问题。所以VC自动化接口生成的
调度代码只适用于它所规定好的那些数据类型，当然这些数据类型已经足够丰富了，但不能满足自定义数据结构的要求。你也可以自己写调度代码来处理你的自定义
数据结构，但这并不是一件容易的事。考虑到IDispatch的种种缺点(它还有一个缺点，就是使用麻烦，:-)
)现在一般都推荐写双接口组件，称为dual接口，实际上就是从IDispatch继承的接口。我们知道任何接口都必须从
IUnknown继承，IDispatch接口也不例外。那从IDispatch继承的接口实际上就等于有两个基类，一个是IUnknown，一个是
IDispatch，所以它可以以两种方式来调用组件，可以通过
IUnknown用虚函数表的方式调用接口方法，也可以通过IDispatch::Invoke自动化调度来调用。这就有了很大的灵活性，这个组件既可以
用于C++的环境也可以用于脚本语言中，同时满足了各方面的需要。 <br /><br />相对比的，dispinterface是一种纯粹的自动化接口，可以简单的就把它看作是IDispatch接口 (虽然它实际上不是的)，这种接口就只能通过自动化的方式来调用，COM组件的事件一般都用的是这种形式的接口。 
<br /><br />Custom接口就是从IUnknown接口派生的类，显然它就只能用虚函数表的方式来调用接口了 
<br /><br />(4) COM组件有三种，进程内、本地、远程。对于后两者情况必须调度接口指针及函数参数。 
<br /><br />COM是一个DLL，它有三种运行模式。它可以是进程内的，即和调用者在同一个进程内，也可以和调用者在同一个机器上但在不同的进程内，还可
以根本就和调用者在两台机器上。这里有一个根本点需要牢记，就是COM组件它只是一个DLL，它自己是运行不起来的，必须有一个进程象父亲般照顾它才行，
即COM组件必须在一个进程内.那谁充当看护人的责任呢？先说说调度的问题。调度是个复杂的问题，以我的知识还讲不清楚这个问题，我只是一般性的谈谈几个
最基本的概念。我们知道对于WIN32程序，每个进程都拥有4GB的虚拟地址空间，每个进程都有其各自的编址，同一个数据块在不同的进程里的编址很可能就
是不一样的，所以存在着进程间的地址转换问题。这就是调度问题。对于本地和远程进程来说，DLL
和客户程序在不同的编址空间，所以要传递接口指针到客户程序必须要经过调度。Windows
已经提供了现成的调度函数，就不需要我们自己来做这个复杂的事情了。对远程组件来说函数的参数传递是另外一种调度。DCOM是以RPC为基础的，要在网络
间传递数据必须遵守标准的网上数据传输协议，数据传递前要先打包，传递到目的地后要解包，这个过程就是调度，这个过程很复杂，不过Windows已经把一
切都给我们做好了，一般情况下我们不需要自己来编写调度DLL。 <br /><br />我们刚说过一个COM组件必须在一个进程内。对于本地模式的组件一般是以EXE的形式出现，所以它本身就已经是一个进程。对于远程DLL，我
们必须找一个进程，这个进程必须包含了调度代码以实现基本的调度。这个进程就是dllhost.exe。这是COM默认的DLL代理。实际上在分布式应用
中，我们应该用MTS来作为DLL代理，因为MTS有着很强大的功能，是专门的用于管理分布式DLL组件的工具。 <br /><br />调度离我们很近又似乎很远，我们编程时很少关注到它，这也是COM的一个优点之一，既平台无关性，无论你是远程的、本地的还是进程内的，编程
是一样的，一切细节都由COM自己处理好了，所以我们也不用深究这个问题，只要有个概念就可以了，当然如果你对调度有自己特殊的要求就需要深入了解调度的
整个过程了，这里推荐一本《COM+技术内幕》，这绝对是一本讲调度的好书。 <br /><br />(5) COM组件的核心是IDL。 
<br /><br />我们希望软件是一块块拼装出来的，但不可能是没有规定的胡乱拼接，总是要遵守一定的标准，各个模块之间如何才能亲密无间的合作，必须要事先共
同制订好它们之间交互的规范，这个规范就是接口。我们知道接口实际上都是纯虚类，它里面定义好了很多的纯虚函数，等着某个组件去实现它，这个接口就是两个
完全不相关的模块能够组合在一起的关键试想一下如果我们是一个应用软件厂商，我们的软件中需要用到某个模块，我们没有时间自己开发，所以我们想到市场上找
一找看有没有这样的模块，我们怎么去找呢？也许我们需要的这个模块在业界已经有了标准，已经有人制订好了标准的接口，有很多组件工具厂商已经在自己的组件
中实现了这个接口，那我们寻找的目标就是这些已经实现了接口的组件，我们不关心组件从哪来，它有什么其它的功能，我们只关心它是否很好的实现了我们制订好
的接口。这种接口可能是业界的标准，也可能只是你和几个厂商之间内部制订的协议，但总之它是一个标准，是你的软件和别人的模块能够组合在一起的基础，是
COM组件通信的标准。 <br /><br />COM具有语言无关性，它可以用任何语言编写，也可以在任何语言平台上被调用。但至今为止我们一直是以C++的环境中谈COM，那它的语言无
关性是怎么体现出来的呢？或者换句话说，我们怎样才能以语言无关的方式来定义接口呢？前面我们是直接用纯虚类的方式定义的，但显然是不行的，除了C++谁
还认它呢？正是出于这种考虑，微软决定采用IDL来定义接口。说白了，IDL实际上就是一种大家都认识的语言，用它来定义接口，不论放到哪个语言平台上都
认识它。我们可以想象一下理想的标准的组件模式，我们总是从IDL开始，先用IDL制订好各个接口，然后把实现接口的任务分配不同的人，有的人可能善长用
VC，有的人可能善长用VB，这没关系，作为项目负责人我不关心这些，我只关心你把最终的DLL
拿给我。这是一种多么好的开发模式，可以用任何语言来开发，也可以用任何语言来欣赏你的开发成果。 <br /><br />(6) COM组件的运行机制，即COM是怎么跑起来的。 
<br /><br />这部分我们将构造一个创建COM组件的最小框架结构，然后看一看其内部处理流程是怎样的 
<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><font face="Courier New"><span style="color: rgb(0, 128, 128);">1</span> <span style="color: rgb(0, 0, 0);">IUnknown</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> pUnk </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> NULL;<br /></span><span style="color: rgb(0, 128, 128);">2</span> <span style="color: rgb(0, 0, 0);">IObject</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> pObject </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> NULL;<br /></span><span style="color: rgb(0, 128, 128);">3</span> <span style="color: rgb(0, 0, 0);">CoInitialize(NULL);<br /></span><span style="color: rgb(0, 128, 128);">4</span> <span style="color: rgb(0, 0, 0);">CoCreateInstance(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IUnknown, (</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">**</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">pUnk);<br /></span><span style="color: rgb(0, 128, 128);">5</span> <span style="color: rgb(0, 0, 0);">pUnk</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);">QueryInterface(IID_IOjbect, (</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">**</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">pObject);<br /></span><span style="color: rgb(0, 128, 128);">6</span> <span style="color: rgb(0, 0, 0);">pUnk</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);">Release();<br /></span><span style="color: rgb(0, 128, 128);">7</span> <span style="color: rgb(0, 0, 0);">pObject</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);">Func();<br /></span><span style="color: rgb(0, 128, 128);">8</span> <span style="color: rgb(0, 0, 0);">pObject</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);">Release();<br /></span><span style="color: rgb(0, 128, 128);">9</span> <span style="color: rgb(0, 0, 0);">CoUninitialize();</span></font></div><br />这就是一个典型的创建COM组件的框架，不过我的兴趣在CoCreateInstance身上，让我们来看看它内部做了一些什么事情。以下是它内部实现的一个伪代码: 
<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> <font face="Courier New">1</font></span><font face="Courier New"> <span style="color: rgb(0, 0, 0);">CoCreateInstance(..) {<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);">    ..<br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">    IClassFactory</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> pClassFactory </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> NULL;<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">    CoGetClassObject(CLSID_Object,<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">                     CLSCTX_INPROC_SERVER,<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">                     NULL,<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">                     IID_IClassFactory,<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);">                     (</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">**</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">pClassFactory);<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">    pClassFactory</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);">CreateInstance(NULL, IID_IUnknown, (</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">**</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">pUnk);<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);">    pClassFactory</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);">Release();<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">    ..<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">}</span></font></div><br />
这段话的意思就是先得到类厂对象，再通过类厂创建组件从而得到IUnknown指针。继续深入一步，看看CoGetClassObject的内部伪码： 
<br /><br />　　　CoGetClassObject(.....)
<br />　　　{
<br />　　　　//通过查注册表CLSID_Object，得知组件DLL的位置、文件名
<br />　　　　//装入DLL库
<br />　　　　//使用函数GetProcAddress(...)得到DLL库中函数DllGetClassObject的函数指针。
<br />　　　　//调用DllGetClassObject 
<br />　　　}
<br />　　　　DllGetClassObject是干什么的，它是用来获得类厂对象的。只有先得到类厂才能去创建组件.
<br />　　　　下面是DllGetClassObject的伪码：
<br />　　　　DllGetClassObject(...)
<br />　　　　{
<br />　　　　......
<br />　　　　CFactory* pFactory= new CFactory; //类厂对象
<br />　　　　pFactory-&gt;QueryInterface(IID_IClassFactory, (void**)&amp;pClassFactory);
<br />　　　　//查询IClassFactory指针
<br />　　　　pFactory-&gt;Release();
<br />　　　　......
<br />　　　　}
<br />　　　　CoGetClassObject的流程已经到此为止，现在返回CoCreateInstance，看看CreateInstance的伪码：
<br />　　　　CFactory::CreateInstance(.....)
<br />　　　　{
<br />　　　　...........
<br />　　　　CObject *pObject = new CObject; //组件对象
<br />　　　　pObject-&gt;QueryInterface(IID_IUnknown, (void**)&amp;pUnk);
<br />　　　　pObject-&gt;Release();
<br />　　　　...........
<br />　　　　} 
<br /><br /><br />(7) 一个典型的自注册的COM DLL所必有的四个函数 
<br /><br />DllGetClassObject:用于获得类厂指针 
<br />
DllRegisterServer:注册一些必要的信息到注册表中 
<br />
DllUnregisterServer:卸载注册信息 
<br />
DllCanUnloadNow:系统空闲时会调用这个函数，以确定是否可以卸载DLL 
<br /><br />DLL还有一个函数是DllMain,这个函数在COM中并不要求一定要实现它，但是在VC生成的组件中自动都包含了它，它的作用主要是得到一个全局的实例对象。 
<br /><br />(8) 注册表在COM中的重要作用 
<br /><br />首先要知道GUID的概念，COM中所有的类、接口、类型库都用GUID来唯一标识，GUID是一个128位的字串，根据特制算法生成的
GUID可以保证是全世界唯一的。
COM组件的创建，查询接口都是通过注册表进行的。有了注册表，应用程序就不需要知道组件的DLL文件名、位置，只需要根据CLSID查就可以了。当版本
升级的时侯，只要改一下注册表信息就可以神不知鬼不觉的转到新版本的DLL。 <br /><br />本文是本人一时兴起的涂鸭之作，讲得并不是很全面，还有很多有用的体会没写出来，以后如果有时间有兴趣再写出来。希望这篇文章能给大家带来一点用处，那我一晚上的辛苦就没有白费了。-:)<br /><br /><img src ="http://www.cppblog.com/heavyz/aggbug/9777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heavyz/" target="_blank">ZHENG Zhong</a> 2006-07-12 19:56 <a href="http://www.cppblog.com/heavyz/archive/2006/07/12/9777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转] 如何在C/C++中调用Java的方法</title><link>http://www.cppblog.com/heavyz/archive/2006/07/04/9356.html</link><dc:creator>ZHENG Zhong</dc:creator><author>ZHENG Zhong</author><pubDate>Mon, 03 Jul 2006 21:15:00 GMT</pubDate><guid>http://www.cppblog.com/heavyz/archive/2006/07/04/9356.html</guid><wfw:comment>http://www.cppblog.com/heavyz/comments/9356.html</wfw:comment><comments>http://www.cppblog.com/heavyz/archive/2006/07/04/9356.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heavyz/comments/commentRss/9356.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heavyz/services/trackbacks/9356.html</trackback:ping><description><![CDATA[原贴地址：<a href="http://xiangchao.yculblog.com/post.830381.html">http://xiangchao.yculblog.com/post.830381.html</a><br /><br />JNI允许运行在虚拟机的Java程序能够与其它语言（例如C和C++）编写的程序或者类库进行相互间的调用。同时JNI提供的一整套的API，允许将Java虚拟机直接嵌入到本地的应用程序中。<br /><br />本文将介绍如何在C/C++中调用Java方法，并结合可能涉及到的问题介绍整个开发的步骤及可能遇到的难题和解决方法。本文所采用的工具是 Sun公司创建的 Java Development Kit (JDK) 版本 1.3.1，以及微软公司的Visual C++ 6开发环境。<br />　　<br /><b>环境搭建</b><br /><br />为了让本文以下部分的代码能够正常工作，我们必须建立一个完整的开发环境。首先需要下载并安装JDK 1.3.1，其下载地址为http://java.sun.com。假设安装路径为C:\JDK。下一步就是设置集成开发环境，通过Visual C++ 6的菜单Tools/Options打开选项对话框。<br />　　<br />将目录C:\JDK\include和C:\JDK\include\win32加入到开发环境的Include Files目录中，同时将C:\JDK\lib目录添加到开发环境的Library Files目录中。这三个目录是JNI定义的一些常量、结构及方法的头文件和库文件。集成开发环境已经设置完毕，同时为了执行程序需要把Java虚拟机所用到的动态链接库所在的目录C:\JDK\jre\bin\classic设置到系统的Path环境变量中。这里需要提出的是，某些开发人员为了方便直接将JRE所用到的DLL文件直接拷贝到系统目录下。这样做是不行的，将导致初始化Java虚拟机环境失败（返回值-1），原因是Java虚拟机是以相对路径来寻找所用到的库文件和其它一些相关文件的。至此整个JNI的开发环境设置完毕，为了让此次JNI旅程能够顺利进行，还必须先准备一个Java类。在这个类中将用到Java中几乎所有有代表性的属性及方法，如静态方法与属性、数组、异常抛出与捕捉等。我们定义的Java程序(Demo.java)如下，本文中所有的代码演示都将基于该Java 程序，代码如下：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">package</span><span style="color: rgb(0, 0, 0);"> jni.test;<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 128, 0);">　　* 该类是为了演示JNI如何访问各种对象属性等<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 128, 0);">　　* </span><span style="color: rgb(128, 128, 128);">@author</span><span style="color: rgb(0, 128, 0);"> liudong<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 128, 0);">　　</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Demo {<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">用于演示如何访问静态的基本类型属性</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> COUNT </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">8</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">演示对象型属性</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String msg;<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">[] counts;<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Demo() {<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">缺省构造函数</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);">　　}<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 128, 0);">　　 * 演示如何访问构造器<br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 128, 0);">　　 </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Demo(String msg) {<br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);">　　 System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&lt;init&gt;:</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> msg);<br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);">　　 </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.msg </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> msg;<br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);">　　 </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.counts </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 0, 0);">　　}<br /></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 128, 0);">　　 * 该方法演示如何访问一个访问以及中文字符的处理<br /></span><span style="color: rgb(0, 128, 128);">25</span> <span style="color: rgb(0, 128, 0);">　　 </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">26</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getMessage() {<br /></span><span style="color: rgb(0, 128, 128);">27</span> <span style="color: rgb(0, 0, 0);">　　 </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> msg;<br /></span><span style="color: rgb(0, 128, 128);">28</span> <span style="color: rgb(0, 0, 0);">　　}<br /></span><span style="color: rgb(0, 128, 128);">29</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">30</span> <span style="color: rgb(0, 128, 0);">　　 * 演示数组对象的访问<br /></span><span style="color: rgb(0, 128, 128);">31</span> <span style="color: rgb(0, 128, 0);">　　 </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">32</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">[] getCounts() {<br /></span><span style="color: rgb(0, 128, 128);">33</span> <span style="color: rgb(0, 0, 0);">　　 </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> counts;<br /></span><span style="color: rgb(0, 128, 128);">34</span> <span style="color: rgb(0, 0, 0);">　　}<br /></span><span style="color: rgb(0, 128, 128);">35</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">36</span> <span style="color: rgb(0, 128, 0);">　　 * 演示如何构造一个数组对象<br /></span><span style="color: rgb(0, 128, 128);">37</span> <span style="color: rgb(0, 128, 0);">　　</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">38</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setCounts(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">[] counts) {<br /></span><span style="color: rgb(0, 128, 128);">39</span> <span style="color: rgb(0, 0, 0);">　　 </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.counts </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> counts;<br /></span><span style="color: rgb(0, 128, 128);">40</span> <span style="color: rgb(0, 0, 0);">　　}<br /></span><span style="color: rgb(0, 128, 128);">41</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">42</span> <span style="color: rgb(0, 128, 0);">　　 * 演示异常的捕捉<br /></span><span style="color: rgb(0, 128, 128);">43</span> <span style="color: rgb(0, 128, 0);">　　</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">44</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> throwExcp() </span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);"> IllegalAccessException {<br /></span><span style="color: rgb(0, 128, 128);">45</span> <span style="color: rgb(0, 0, 0);">　　 </span><span style="color: rgb(0, 0, 255);">throw</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> IllegalAccessException(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">exception occur.</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">46</span> <span style="color: rgb(0, 0, 0);">　　}<br /></span><span style="color: rgb(0, 128, 128);">47</span> <span style="color: rgb(0, 0, 0);">　　}</span></div>　　<br /><b>初始化虚拟机</b><br /><br />本地代码在调用Java方法之前必须先加载Java虚拟机，而后所有的Java程序都在虚拟机中执行。为了初始化Java虚拟机，JNI提供了一系列的接口函数Invocation API。通过这些API可以很方便地将虚拟机加载到内存中。创建虚拟机可以用函数<font face="Courier New">jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args)</font>。对于这个函数有一点需要注意的是，在JDK 1.1中第三个参数总是指向一个结构<font face="Courier New">JDK1_1InitArgs</font>，这个结构无法完全在所有版本的虚拟机中进行无缝移植。在JDK 1.2中已经使用了一个标准的初始化结构<font face="Courier New">JavaVMInitArgs</font>来替代<font face="Courier New">JDK1_1InitArgs</font>。下面我们分别给出两种不同版本的示例代码。<br /><br />在JDK 1.1初始化虚拟机:<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><font face="Courier New"><span style="color: rgb(0, 128, 128);"> 1</span><span style="color: rgb(0, 0, 0);">#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">jni.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 2</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> main() {<br /></span><span style="color: rgb(0, 128, 128);"> 3</span>     <span style="color: rgb(0, 0, 0);">JNIEnv </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">env;<br /></span><span style="color: rgb(0, 128, 128);"> 4</span>     <span style="color: rgb(0, 0, 0);">JavaVM </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">jvm;<br /></span><span style="color: rgb(0, 128, 128);"> 5</span>     <span style="color: rgb(0, 0, 0);">JDK1_1InitArgs vm_args;<br /></span><span style="color: rgb(0, 128, 128);"> 6</span>     <span style="color: rgb(0, 0, 0);">jint res;<br /></span><span style="color: rgb(0, 128, 128);"> 7</span>     <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);"> IMPORTANT: 版本号设置一定不能漏 </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 8</span>     <span style="color: rgb(0, 0, 0);">vm_args.version </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0x00010001</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);"> 9</span><span style="color: rgb(0, 0, 0);">     </span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);"> 获取缺省的虚拟机初始化参数</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">10</span>     <span style="color: rgb(0, 0, 0);">JNI_GetDefaultJavaVMInitArgs(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">vm_args);<br /></span><span style="color: rgb(0, 128, 128);">11</span>     <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);"> 添加自定义的类路径 </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">12</span>     <span style="color: rgb(0, 0, 0);">sprintf(classpath, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%s%c%s</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,<br /></span><span style="color: rgb(0, 128, 128);">13</span>             <span style="color: rgb(0, 0, 0);">vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);<br /></span><span style="color: rgb(0, 128, 128);">14</span>     <span style="color: rgb(0, 0, 0);">vm_args.classpath </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> classpath;<br /></span><span style="color: rgb(0, 128, 128);">15</span>     <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">/* </span><span style="color: rgb(0, 128, 0);">设置一些其他的初始化参数</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">16</span>     <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);"> 创建虚拟机 </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">17</span>     <span style="color: rgb(0, 0, 0);">res </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> JNI_CreateJavaVM(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">jvm,</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">env,</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">vm_args);<br /></span><span style="color: rgb(0, 128, 128);">18</span>     <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (res </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">) {<br /></span><span style="color: rgb(0, 128, 128);">19</span>         <span style="color: rgb(0, 0, 0);">fprintf(stderr, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Can't create Java VM\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">20</span>         <span style="color: rgb(0, 0, 0);">exit(</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">21</span>     <span style="color: rgb(0, 0, 0);">}<br /></span><span style="color: rgb(0, 128, 128);">22</span>     <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);">释放虚拟机资源</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">23</span>     <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">jvm)</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);">DestroyJavaVM(jvm);<br /></span><span style="color: rgb(0, 128, 128);">24</span><span style="color: rgb(0, 0, 0);">}<br /></span><span style="color: rgb(0, 128, 128);">25</span> </font><span style="color: rgb(0, 0, 0);"></span></div><br /><br />JDK 1.2初始化虚拟机：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);"> invoke2.c </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);">　　#include </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">jni.h</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> main() {<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> res;<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">　　JavaVM </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">jvm;<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">　　JNIEnv </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">env;<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">　　JavaVMInitArgs vm_args;<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);">　　JavaVMOption options[</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">];<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">　　vm_args.version</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">JNI_VERSION_1_2;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">这个字段必须设置为该值</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);">设置初始化参数</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">　　options[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">].optionString </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">-Djava.compiler=NONE</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">　　options[</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">].optionString </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">-Djava.class.path=.</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">　　options[</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">].optionString </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">-verbose:jni</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">; </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">用于跟踪运行时的信息</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);">版本号设置不能漏</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">　　vm_args.version </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> JNI_VERSION_1_2;<br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);">　　vm_args.nOptions </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">;<br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 0, 0);">　　vm_args.options </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> options;<br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);">　　vm_args.ignoreUnrecognized </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> JNI_TRUE;<br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);">　　res </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> JNI_CreateJavaVM(</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">jvm, (</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">**</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">env, </span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">vm_args);<br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);">　　</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (res </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">) {<br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);">　　 fprintf(stderr, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Can't create Java VM\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 0, 0);">　　 exit(</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);">　　}<br /></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 0, 0);">　　(</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">jvm)</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);">DestroyJavaVM(jvm);<br /></span><span style="color: rgb(0, 128, 128);">25</span> <span style="color: rgb(0, 0, 0);">　　fprintf(stdout, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Java VM destory.\n</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br /></span><span style="color: rgb(0, 128, 128);">26</span> <span style="color: rgb(0, 0, 0);">　　}</span></div><br />为了保证JNI代码的可移植性，建议使用JDK 1.2的方法来创建虚拟机。<font face="Courier New">JNI_CreateJavaVM</font>函数的第二个参数<font face="Courier New">JNIEnv *env</font>，就是贯穿整个JNI始末的一个参数，因为几乎所有的函数都要求一个参数就是<font face="Courier New">JNIEnv *env</font>。<br /><br /><b>访问类方法</b><br /><br />初始化了Java虚拟机后，就可以开始调用Java的方法。要调用一个Java对象的方法必须经过几个步骤：<br /><br />1.获取指定对象的类定义(<font face="Courier New">jclass</font>)<br /><br />有两种途径来获取对象的类定义：第一种是在已知类名的情况下使用<font face="Courier New">FindClass</font>来查找对应的类。但是要注意类名并不同于平时写的Java代码，例如要得到类<font face="Courier New">jni.test.Demo</font>的定义必须调用如下代码：<br /><br /><font face="Courier New">jclass cls = (*env)-&gt;FindClass(env, "jni/test/Demo"); //把点号换成斜杠</font><br />　　<br />然后通过对象直接得到其所对应的类定义：<br /><br />jclass cls = (*env)-&gt; GetObjectClass(env, obj);<br />//其中obj是要引用的对象，类型是jobject<br /><br />2.读取要调用方法的定义(<font face="Courier New">jmethodID</font>)<br />　　<br />我们先来看看JNI中获取方法定义的函数：<br /><br />　　jmethodID (JNICALL *GetMethodID)(JNIEnv *env, jclass clazz, const char *name,<br />　　const char *sig);<br />　　jmethodID (JNICALL *GetStaticMethodID)(JNIEnv *env, jclass class, const char<br />　　*name, const char *sig);<br /><br />这两个函数的区别在于<font face="Courier New">GetStaticMethodID</font>是用来获取静态方法的定义，<font face="Courier New">GetMethodID</font>则是获取非静态的方法定义。这两个函数都需要提供四个参数：env就是初始化虚拟机得到的JNI环境；第二个参数class是对象的类定义，也就是第一步得到的obj；第三个参数是方法名称；最重要的是第四个参数，这个参数是方法的定义。因为我们知道Java中允许方法的多态，仅仅是通过方法名并没有办法定位到一个具体的方法，因此需要第四个参数来指定方法的具体定义。但是怎么利用一个字符串来表示方法的具体定义呢？JDK中已经准备好一个反编译工具javap，通过这个工具就可以得到类中每个属性、方法的定义。下面就来看看jni.test.Demo的定义：<br /><br />打开命令行窗口并运行 javap -s -p jni.test.Demo 得到运行结果如下：<br />　　<br />　　Compiled from Demo.java<br />　　public class jni.test.Demo extends java.lang.Object {<br />　　public static int COUNT;<br />　　/*　I　*/<br />　　public java.lang.String msg;<br />　　/*　Ljava/lang/String;　*/<br />　　private int counts[];<br />　　/*　[I　*/<br />　　public jni.test.Demo();<br />　　/*　()V　*/<br />　　public jni.test.Demo(java.lang.String);<br />　　/*　(Ljava/lang/String;)V　*/<br />　　public java.lang.String getMessage();<br />　　/*　()Ljava/lang/String;　*/<br />　　public int getCounts()[];<br />　　/*　()[I　*/<br />　　public void setCounts(int[]);<br />　　/*　([I)V　*/<br />　　public void throwExcp() throws java.lang.IllegalAccessException;<br />　　/*　()V　*/<br />　　static {};<br />　　/*　()V　*/<br />　　}<br />　　<br />我们看到类中每个属性和方法下面都有一段注释。注释中不包含空格的内容就是第四个参数要填的内容(关于javap具体参数请查询JDK的使用帮助)。下面这段代码演示如何访问jni.test.Demo的getMessage方法：<br />　　<br />　　/*<br />　　假设我们已经有一个jni.test.Demo的实例obj<br />　　*/<br />　　jmethodID mid;<br />　　jclass cls = (*env)-&gt; GetObjectClass (env, obj); //获取实例的类定义<br />　　mid=(*env)-&gt;GetMethodID(env,cls,"getMessage"," ()Ljava/lang/String; ");<br />　　/*如果mid为0表示获取方法定义失败*/<br />　　jstring msg = (*env)-&gt; CallObjectMethod(env, obj, mid);<br />　　/*<br />　　如果该方法是静态的方法那只需要将最后一句代码改为以下写法即可：<br />　　jstring msg = (*env)-&gt; CallStaticObjectMethod(env, cls, mid);<br />　　*/<br />　　<br />3.调用方法<br /><br />为了调用对象的某个方法，可以使用函数Call&lt;TYPE&gt; Method或者CallStatic&lt;TYPE&gt; Method（访问类的静态方法），&lt;TYPE&gt;根据不同的返回类型而定。这些方法都是使用可变参数的定义，如果访问某个方法需要参数时，只需要把所有参数按照顺序填写到方法中就可以。在讲到构造函数的访问时，将演示如何访问带参数的构造函数。<br />　　<br /><b>访问类属性</b><br /><br />访问类的属性与访问类的方法大体上是一致的，只不过是把方法变成属性而已。<br />　　<br />　　1.获取指定对象的类(jclass)<br />　　<br />　　这一步与访问类方法的第一步完全相同，具体使用参看访问类方法的第一步。<br />　　<br />　　2.读取类属性的定义(jfieldID)<br />　　<br />　　在JNI中是这样定义获取类属性的方法的：<br />　　<br />　　jfieldID (JNICALL *GetFieldID)<br />　　(JNIEnv *env, jclass clazz, const char *name, const char *sig);<br />　　jfieldID (JNICALL *GetStaticFieldID)<br />　　(JNIEnv *env, jclass clazz, const char *name, const char *sig);<br />　　<br />　　这两个函数中第一个参数为JNI环境；clazz为类的定义；name为属性名称；第四个参数同样是为了表达属性的类型。前面我们使用javap工具获取类的详细定义的时候有这样两行：<br />　　<br />　　public java.lang.String msg;<br />　　/*　Ljava/lang/String;　*/<br />　　<br />　　其中第二行注释的内容就是第四个参数要填的信息，这跟访问类方法时是相同的。<br />　　<br />　　3.读取和设置属性值<br />　　<br />　　有了属性的定义要访问属性值就很容易了。有几个方法用来读取和设置类的属性，它们是：Get&lt;TYPE&gt;Field、 Set&lt;TYPE&gt;Field、GetStatic&lt;TYPE&gt;Field、SetStatic&lt;TYPE&gt; Field。比如读取Demo类的msg属性就可以用GetObjectField，而访问COUNT用GetStaticIntField，相关代码如下：<br />　　<br />　　jfieldID field = (*env)-&gt;GetFieldID(env,obj,"msg"," Ljava/lang/String;");<br />　　jstring msg = (*env)-&gt; GetObjectField(env, cls, field); //msg就是对应Demo的msg<br />　　jfieldID field2 = (*env)-&gt;GetStaticFieldID(env,obj,"COUNT","I");<br />　　jint count = (*env)-&gt;GetStaticIntField(env,cls,field2);<br />　　<br /><b>访问构造函数</b><br /><br />很多人刚刚接触JNI的时候往往会在这一节遇到问题，查遍了整个jni.h看到这样一个函数NewObject，它应该是可以用来访问类的构造函数。但是该函数需要提供构造函数的方法定义，其类型是jmethodID。从前面的内容我们知道要获取方法的定义首先要知道方法的名称，但是构造函数的名称怎么来填写呢？其实访问构造函数与访问一个普通的类方法大体上是一样的，惟一不同的只是方法名称不同及方法调用时不同而已。访问类的构造函数时方法名必须填写“&lt;init&gt;”。下面的代码演示如何构造一个Demo类的实例：<br />　　<br />　　jclass cls = (*env)-&gt;FindClass(env, "jni/test/Demo");<br />　　/**<br />　　首先通过类的名称获取类的定义，相当于Java中的Class.forName方法<br />　　*/<br />　　if (cls == 0)<br />　　&lt;error handler&gt;<br />　　jmethodID mid = (*env)-&gt;GetMethodID(env,cls,"&lt;init&gt;","(Ljava/lang/String;)V ");<br />　　if(mid == 0)<br />　　&lt;error handler&gt;<br />　　jobject demo = jenv-&gt;NewObject(cls,mid,0);<br />　　/**<br />　　访问构造函数必须使用NewObject的函数来调用前面获取的构造函数的定义<br />　　上面的代码我们构造了一个Demo的实例并传一个空串null<br />　　*/<br />　　<br /><b>数组处理</b><br /><br />创建一个新数组<br /><br />要创建一个数组，我们首先应该知道数组元素的类型及数组长度。JNI定义了一批数组的类型j&lt;TYPE&gt;Array及数组操作的函数New&lt;TYPE&gt;Array，其中&lt;TYPE&gt;就是数组中元素的类型。例如，要创建一个大小为10并且每个位置值分别为1 －10的整数数组，编写代码如下：<br />　　<br />　　int i = 1;<br />　　jintArray array; //定义数组对象<br />　　(*env)-&gt; NewIntArray(env, 10);<br />　　for(; i&lt;= 10; i++)<br />　　(*env)-&gt;SetIntArrayRegion(env, array, i-1, 1, &amp;i);<br />　　<br />访问数组中的数据<br /><br />访问数组首先应该知道数组的长度及元素的类型。现在我们把创建的数组中的每个元素值打印出来，代码如下：<br />　　<br />　　int i;<br />　　/* 获取数组对象的元素个数 */<br />　　int len = (*env)-&gt;GetArrayLength(env, array);<br />　　/* 获取数组中的所有元素 */<br />　　jint* elems = (*env)-&gt; GetIntArrayElements(env, array, 0);<br />　　for(i=0; i&lt; len; i++)<br />　　printf("ELEMENT %d IS %d\n", i, elems);<br />　　<br />中文处理<br /><br />中文字符的处理往往是让人比较头疼的事情，特别是使用Java语言开发的软件，在JNI这个问题更加突出。由于Java中所有的字符都是 Unicode编码，但是在本地方法中，例如用VC编写的程序，如果没有特殊的定义一般都没有使用Unicode的编码方式。为了让本地方法能够访问 Java中定义的中文字符及Java访问本地方法产生的中文字符串，我定义了两个方法用来做相互转换。<br /><br />方法一，将Java中文字符串转为本地字符串<br />　　<br />　　/**<br />　　第一个参数是虚拟机的环境指针<br />　　第二个参数为待转换的Java字符串定义<br />　　第三个参数是本地存储转换后字符串的内存块<br />　　第三个参数是内存块的大小<br />　　*/<br />　　int JStringToChar(JNIEnv *env, jstring str, LPTSTR desc, int desc_len)<br />　　{<br />　　int len = 0;<br />　　if(desc==NULL||str==NULL)<br />　　return -1;<br />　　//在VC中wchar_t是用来存储宽字节字符(UNICODE)的数据类型<br />　　wchar_t *w_buffer = new wchar_t[1024];<br />　　ZeroMemory(w_buffer,1024*sizeof(wchar_t));<br />　　//使用GetStringChars而不是GetStringUTFChars<br />　　wcscpy(w_buffer,env-&gt;GetStringChars(str,0));<br />　　env-&gt;ReleaseStringChars(str,w_buffer);<br />　　ZeroMemory(desc,desc_len);<br />　　//调用字符编码转换函数(Win32 API)将UNICODE转为ASCII编码格式字符串<br />　　//关于函数WideCharToMultiByte的使用请参考MSDN<br />　　len = WideCharToMultiByte(CP_ACP,0,w_buffer,1024,desc,desc_len,NULL,NULL);<br />　　//len = wcslen(w_buffer);<br />　　if(len&gt;0 &amp;&amp; len&lt;desc_len)<br />　　 desc[len]=0;<br />　　delete[] w_buffer;<br />　　return strlen(desc);<br />　　}<br />　　<br />方法二，将C的字符串转为Java能识别的Unicode字符串<br />　　<br />　　jstring NewJString(JNIEnv* env,LPCTSTR str)<br />　　{<br />　　if(!env || !str)<br />　　 return 0;<br />　　int slen = strlen(str);<br />　　jchar* buffer = new jchar[slen];<br />　　int len = MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,slen);<br />　　if(len&gt;0 &amp;&amp; len &lt; slen)<br />　　 buffer[len]=0;<br />　　jstring js = env-&gt;NewString(buffer,len);<br />　　delete [] buffer;<br />　　return js;<br />　　}<br />　　<br /><b>异常</b><br /><br />由于调用了Java的方法，因此难免产生操作的异常信息。这些异常没有办法通过C++本身的异常处理机制来捕捉到，但JNI可以通过一些函数来获取Java中抛出的异常信息。之前我们在Demo类中定义了一个方法throwExcp，下面将访问该方法并捕捉其抛出来的异常信息，代码如下：<br />　　<br />　　/**<br />　　假设我们已经构造了一个Demo的实例obj，其类定义为cls<br />　　*/<br />　　jthrowable excp = 0; /* 异常信息定义 */<br />　　jmethodID mid=(*env)-&gt;GetMethodID(env,cls,"throwExcp","()V");<br />　　/*如果mid为0表示获取方法定义失败*/<br />　　jstring msg = (*env)-&gt; CallVoidMethod(env, obj, mid);<br />　　/* 在调用该方法后会有一个IllegalAccessException的异常抛出 */<br />　　excp = (*env)-&gt;ExceptionOccurred(env);<br />　　if(excp){<br />　　(*env)-&gt;ExceptionClear(env);<br />　　//通过访问excp来获取具体异常信息<br />　　/*<br />　　在Java中，大部分的异常信息都是扩展类java.lang.Exception，因此可以访问excp的toString<br />　　或者getMessage来获取异常信息的内容。访问这两个方法同前面讲到的如何访问类的方法是相同的。<br />　　*/<br />　　}<br /><br /><br /><b>线程和同步访问</b><br /><br />有些时候需要使用多线程的方式来访问Java的方法。我们知道一个Java虚拟机是非常消耗系统的内存资源，差不多每个虚拟机需要内存大约在 20MB左右。为了节省资源要求每个线程使用的是同一个虚拟机，这样在整个的JNI程序中只需要初始化一个虚拟机就可以了。所有人都是这样想的，但是一旦子线程访问主线程创建的虚拟机环境变量，系统就会出现错误对话框，然后整个程序终止。<br /><br />其实这里面涉及到两个概念，它们分别是虚拟机(JavaVM *jvm)和虚拟机环境（JNIEnv *env）。真正消耗大量系统资源的是jvm而不是env，jvm是允许多个线程访问的，但是env只能被创建它本身的线程所访问，而且每个线程必须创建自己的虚拟机环境env。这时候会有人提出疑问，主线程在初始化虚拟机的时候就创建了虚拟机环境env。为了让子线程能够创建自己的env，JNI提供了两个函数：AttachCurrentThread和DetachCurrentThread。下面代码就是子线程访问Java方法的框架：<br />　　<br />　　DWORD WINAPI ThreadProc(PVOID dwParam)<br />　　{<br />　　JavaVM jvm = (JavaVM*)dwParam; /* 将虚拟机通过参数传入 */<br />　　JNIEnv* env;<br />　　(*jvm)-&gt; AttachCurrentThread(jvm, (void**)&amp;env, NULL);<br />　　.........<br />　　(*jvm)-&gt; DetachCurrentThread(jvm);<br />　　}<br />　　<br /><b>时间</b><br /><br />关于时间的话题是我在实际开发中遇到的一个问题。当要发布使用了JNI的程序时，并不一定要求客户要安装一个Java运行环境，因为可以在安装程序中打包这个运行环境。为了让打包程序利于下载，这个包要比较小，因此要去除JRE（Java运行环境）中一些不必要的文件。但是如果程序中用到 Java中的日历类型，例如java.util.Calendar等，那么有个文件一定不能去掉，这个文件就是[JRE]\lib\tzmappings。它是一个时区映射文件，一旦没有该文件就会发现时间操作上经常出现与正确时间相差几个小时的情况。下面是打包JRE中必不可少的文件列表(以Windows环境为例)，其中[JRE]为运行环境的目录，同时这些文件之间的相对路径不能变。<br /><br />文件名 目录<br />　　hpi.dll [JRE]\bin<br />　　ioser12.dll [JRE]\bin<br />　　java.dll [JRE]\bin<br />　　net.dll [JRE]\bin<br />　　verify.dll [JRE]\bin<br />　　zip.dll [JRE]\bin<br />　　jvm.dll [JRE]\bin\classic<br />　　rt.jar [JRE]\lib<br />　　tzmappings [JRE]\lib<br />　　<br />由于rt.jar有差不多10MB，但是其中有很大一部分文件并不需要，可以根据实际的应用情况进行删除。例如程序如果没有用到Java Swing，就可以把涉及到Swing的文件都删除后重新打包。<img src ="http://www.cppblog.com/heavyz/aggbug/9356.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heavyz/" target="_blank">ZHENG Zhong</a> 2006-07-04 05:15 <a href="http://www.cppblog.com/heavyz/archive/2006/07/04/9356.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DocBook, DocBook XSL and xsltproc</title><link>http://www.cppblog.com/heavyz/archive/2006/07/03/9336.html</link><dc:creator>ZHENG Zhong</dc:creator><author>ZHENG Zhong</author><pubDate>Mon, 03 Jul 2006 12:13:00 GMT</pubDate><guid>http://www.cppblog.com/heavyz/archive/2006/07/03/9336.html</guid><wfw:comment>http://www.cppblog.com/heavyz/comments/9336.html</wfw:comment><comments>http://www.cppblog.com/heavyz/archive/2006/07/03/9336.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/heavyz/comments/commentRss/9336.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/heavyz/services/trackbacks/9336.html</trackback:ping><description><![CDATA[Customization of the stylesheet:<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><font face="Courier New"><span style="color: rgb(0, 128, 128);"> 1</span><span style="color: rgb(0, 0, 255);">&lt;?</span><span style="color: rgb(255, 0, 255);">xml version='1.0'</span><span style="color: rgb(0, 0, 255);">?&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">xsl:stylesheet </span><span style="color: rgb(255, 0, 0);">xmlns:xsl</span><span style="color: rgb(0, 0, 255);">="http://www.w3.org/1999/XSL/Transform"</span><span style="color: rgb(255, 0, 0);"> version</span><span style="color: rgb(0, 0, 255);">="1.0"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">xsl:import </span><span style="color: rgb(255, 0, 0);">href</span><span style="color: rgb(0, 0, 255);">="xhtml/docbook.xsl"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">xsl:param </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="html.stylesheet"</span><span style="color: rgb(255, 0, 0);"> select</span><span style="color: rgb(0, 0, 255);">="'style.css'"</span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">  <br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 128, 0);">&lt;!--</span><span style="color: rgb(0, 128, 0);">xsl:param name="generate.toc"&gt;<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 128, 0);">    appendix  nop<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 128, 0);">    article   toc,title<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 128, 0);">    book      toc,title,figure,table,example,equation<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 128, 0);">    chapter   toc<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 128, 0);">    part      nop<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 128, 0);">    preface   nop<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 128, 0);">    qandadiv  nop<br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 128, 0);">    qandaset  nop<br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 128, 0);">    reference toc,title<br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 128, 0);">    section   nop<br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 128, 0);">    set       toc<br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 128, 0);">  &lt;/xsl:param</span><span style="color: rgb(0, 128, 0);">--&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);">  <br /></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">xsl:param </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="generate.toc"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);">    appendix  nop<br /></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 0, 0);">    article   nop<br /></span><span style="color: rgb(0, 128, 128);">25</span> <span style="color: rgb(0, 0, 0);">    book      nop<br /></span><span style="color: rgb(0, 128, 128);">26</span> <span style="color: rgb(0, 0, 0);">    chapter   nop<br /></span><span style="color: rgb(0, 128, 128);">27</span> <span style="color: rgb(0, 0, 0);">    part      nop<br /></span><span style="color: rgb(0, 128, 128);">28</span> <span style="color: rgb(0, 0, 0);">    preface   nop<br /></span><span style="color: rgb(0, 128, 128);">29</span> <span style="color: rgb(0, 0, 0);">    qandadiv  nop<br /></span><span style="color: rgb(0, 128, 128);">30</span> <span style="color: rgb(0, 0, 0);">    qandaset  nop<br /></span><span style="color: rgb(0, 128, 128);">31</span> <span style="color: rgb(0, 0, 0);">    reference nop<br /></span><span style="color: rgb(0, 128, 128);">32</span> <span style="color: rgb(0, 0, 0);">    section   nop<br /></span><span style="color: rgb(0, 128, 128);">33</span> <span style="color: rgb(0, 0, 0);">    set       nop<br /></span><span style="color: rgb(0, 128, 128);">34</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">xsl:param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">35</span> <span style="color: rgb(0, 0, 0);">  <br /></span><span style="color: rgb(0, 128, 128);">36</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">xsl:template </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="user.header.navigation"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">37</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">font </span><span style="color: rgb(255, 0, 0);">color</span><span style="color: rgb(0, 0, 255);">="red"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">user.header.navigation</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">font</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">38</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">xsl:template</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">39</span> <span style="color: rgb(0, 0, 0);">  <br /></span><span style="color: rgb(0, 128, 128);">40</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">xsl:template </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="user.header.content"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">41</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">font </span><span style="color: rgb(255, 0, 0);">color</span><span style="color: rgb(0, 0, 255);">="red"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">user.header.content</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">font</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">42</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">xsl:template</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">43</span> <span style="color: rgb(0, 0, 0);">  <br /></span><span style="color: rgb(0, 128, 128);">44</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">xsl:template </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="user.footer.content"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">45</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">font </span><span style="color: rgb(255, 0, 0);">color</span><span style="color: rgb(0, 0, 255);">="red"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">user.footer.content</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">font</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">46</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">xsl:template</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">47</span> <span style="color: rgb(0, 0, 0);">  <br /></span><span style="color: rgb(0, 128, 128);">48</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">xsl:template </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="user.footer.navigation"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">49</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">hr </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">50</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">font </span><span style="color: rgb(255, 0, 0);">color</span><span style="color: rgb(0, 0, 255);">="red"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">user.footer.navigation</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">font</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">51</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">hr </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">52</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">xsl:template</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">53</span> <span style="color: rgb(0, 0, 0);">  <br /></span><span style="color: rgb(0, 128, 128);">54</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">xsl:stylesheet</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 128);"></span><span style="color: rgb(0, 0, 0);"></span></font><br /></div><br />A sample docbook article:<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><font face="Courier New"><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">&lt;?</span><span style="color: rgb(255, 0, 255);">xml version="1.0" encoding="UTF-8"</span><span style="color: rgb(0, 0, 255);">?&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">&lt;!</span><span style="color: rgb(255, 0, 255);">DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"<br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(255, 0, 255);">                  "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">article </span><span style="color: rgb(255, 0, 0);">lang</span><span style="color: rgb(0, 0, 255);">="zh-CN"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">The title of the article</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">articleinfo</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">author</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">firstname</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">Zhong</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">firstname</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">surname</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">ZHENG</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">surname</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">author</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">date</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">July 05, 2006</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">date</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">articleinfo</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">para</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">This is a paragraph.</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">para</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">para</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">This is another paragraph.</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">para</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">section </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="sect1"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">The title of a section</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">subtitle</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">It even has a subtitle</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">subtitle</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">para</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">The paragraph of the section.</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">para</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">section</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">article</span><span style="color: rgb(0, 0, 255);">&gt;</span></font></div><br />To generate HTML output, use the following commands:<br /><br />set SGML_CATALOG_FILES=path/to/catalog.xml<br />xsltproc --catalogs --output path/to/generated/output.html path/to/customization.xsl path/to/docbook/source.xml<br /><br /><img src ="http://www.cppblog.com/heavyz/aggbug/9336.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/heavyz/" target="_blank">ZHENG Zhong</a> 2006-07-03 20:13 <a href="http://www.cppblog.com/heavyz/archive/2006/07/03/9336.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>