<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Chris的空间</title>
    <description></description>
    <link>http://vanadies10.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>InnoDB 和 MyISAM中的Blob</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/208378" style="color:red;">http://vanadies10.javaeye.com/blog/208378</a>&nbsp;
          发表时间: 2008年06月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最近在用的一直是Mysql的Innodb，昨天测试了一下包含Blob字段的数据的插入，真的是很惨不忍睹。在表中记录数小于2k的时候，速度还行，超过2k速度就下降，从470/s持续的下降，在表中有1w条记录的时候速度就只有240/s了。到5w的时候，就只有178/s了。到20w的时候，则是130/s。后来换成了Myisam，基本上在200w记录的时候还能够有1000/s的速度。Myisam不支持事务，速度快，这些都是很早就知道的。只是不知道会有这么大的差距。也不清楚是不是innodb的什么设置我没有设置正确。现在从性能上考虑，要采用MyISAM了。而不能保证事务的这个现实，需要在APP上进行处理了。这个差距真的是太惊人了。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; 不过如果没有Blob等字段，只有简单类型的话，InnoDB还好了。性能还说的过去。并且关键的是不会因为表中的有一些数据而导致性能急剧下降。<br />
</div>
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/208378#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 26 Jun 2008 22:02:40 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/208378</link>
        <guid>http://vanadies10.javaeye.com/blog/208378</guid>
      </item>
      <item>
        <title>DBCP</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188693" style="color:red;">http://vanadies10.javaeye.com/blog/188693</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DBCP是apache下面的一个开源的数据库连接池，谈谈几个经验</p>
<p>1 Connection出问题后的释放</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection建立成功后，如果在某次操作的时候，连接本身出现异常，可能需要废弃掉这个连接，创建新连接。当然对于mysql，支持autoReconnect的则不存在问题(Connection本身不需要废弃)，但是如果不支持autoReconnect的driver，就存在这个问题。DBCP中使用的是PoolableConnection，关闭的时候，判断PoolableConnection是否close，因为这个PoolableConnection上还有代理，所以不会重复关闭，那么就判断底层的Connection的isClosed是否为true，如果是true，那么就会丢弃这个连接。JDK中Connection接口的isClosed只在Connection.close被调用后为true，在Driver的实现上，产生和数据库连接的异常后，Driver必须要自己调用close方法，才能保证这个地方让DBCP去丢弃连接。另外就是在close的时候，还调用了ConnectionFactory的passiveObject方法，这个地方出异常也会导致连接被丢弃掉。</p>
<p>2 关于Idle</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认DBCP的minIdle和maxIdle都是-1，设置以后的话，对于maxIdle，如果maxIdle小于maxActive，那么在调用returnObject的时候，如果当前的idle已经等于maxIdle了，会释放掉这个连接。</p>
<p>3 evict</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 如果设置了evict的time，那么会启动一个evictor的线程，这个是对idle的object进行检查的。基本上的逻辑是验证idle的object，删除idle超时的object，然后要保证idle的数量到达minIdle的值。</p>
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188693#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:33:49 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188693</link>
        <guid>http://vanadies10.javaeye.com/blog/188693</guid>
      </item>
      <item>
        <title>LoadRunner lrs_send发送数据</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188682" style="color:red;">http://vanadies10.javaeye.com/blog/188682</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          LoadRunner的lrs_一族的函数是socket操作的函数，可以方便的创建、释放socket，并通过创建的socket收发数据。socket发送的数据可以是固定的数据，也可以是在buffer中使用param来使得发送的内容具有动态 性。那么如果这个param是从用户自定义函数中返回的，那么存在一个没有办法释放的问题。那么有没有什么更好的办法呢。一个办法是通过加载dll，然后传入一个char[]来获取生成的信息，然后把这个信息写给一个buffer，然后发送这个buffer，还有一个方式就是直接发送char[]中的内容，第一种方法要使用lrs_save_param或者lrs_save_param_ex来保存数据到param中，但是我自己没有实验成功过。第二种可以通过lrs_set_send_buffer调用使得发送的buffer就是我们的char[].那么在这个函数调用后，lrs_send中的第二个参数，也就是buffer的名称就没有意义了。
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188682#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:16:12 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188682</link>
        <guid>http://vanadies10.javaeye.com/blog/188682</guid>
      </item>
      <item>
        <title>LoadRunnder 使用外部的动态链接库</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188681" style="color:red;">http://vanadies10.javaeye.com/blog/188681</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          在LoadRunner中使用外部的动态链接库有两种方式，一种是通过Param，另外一个就是直接加载并且使用。开始看到网上有人说是用dll中的函数的话，返回不能是字符串，另外就是参数是字符串的也是只读的，不能更改。这样的话，调用dll就真的是限制太大了。不过后来测试发现，不存在上面两个限制的。<br /><br />通过Param来使用 外部的dll，要设置Param的类型是User Defined Function,设置dll的路径和方法名称，这个方法貌似是不能有参数的。这样就可以使用了。不过对于这样的方式，Param的值是从函数返回的，返回字符串就比较麻烦了。因为返回字符串，除非是常量字符串，否则都要new(malloc)那么没有地方去释放。<br /><br />另外一种方式就是类似于C的写法了，直接使用lr_load_dll加载动态链接库，然后直接使用动态链接库中的函数，不过这里面要注意一点，如果函数返回值不是int，要事先声明一下，就是要在代码头部写 extern char * yourFunc();就可以使用了。开始在写C的时候，忘了C必须在代码前定义变量，而不能在代码中定义，然后编译出错，看看是写在Action中，以为有什么限制，很是不解，后来是在另外一个同事那里又试的时候，想到的。唉。基础都忘了。另外就是如果需要dll中产生以下数据，传递接收的buffer给函数，在dll外部分配好空间。这很重要，因为dll内部分配的内存在外部是没有办法直接释放的，因为EXE和DLL，也包括多个dll都是由自己独立的堆的！！！
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188681#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:15:57 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188681</link>
        <guid>http://vanadies10.javaeye.com/blog/188681</guid>
      </item>
      <item>
        <title>上帝会保佑我们的--来个技术无关的。</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188679" style="color:red;">http://vanadies10.javaeye.com/blog/188679</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          一个人溺水，等上帝来救他。来了一艘船要救他，他说不，上帝回来救我的，船走了。后来又有两艘船路过要救他，被他用同样的理由拒绝了，结果这个人被淹死了。当他碰见上帝时，他说，上帝啊，我是这么的信仰你，你为什么没有来救我呢？上帝说，我已经派了三艘船去救你，你都拒绝了，上帝也没有办法救你了！ <br /><br />其实很多事情，自己要有好的心态。这很重要！！！
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188679#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:15:34 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188679</link>
        <guid>http://vanadies10.javaeye.com/blog/188679</guid>
      </item>
      <item>
        <title>Eclipse下XmlBuddy和jpdl-gpd的冲突</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188677" style="color:red;">http://vanadies10.javaeye.com/blog/188677</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          近日想学习一下jBPM，看到有一个插件可以图形化的进行流程的编辑，就下载了一个。就是jbpm中的jpdl-gpd。上次在兄弟公司看到他们的技术人员在介绍jbpm在他们那边的应用。上周就下载了jbpm，似乎现在的版本比较新了一点儿。以前还有一个starter-kit，现在貌似没有了。自己下载好了以后，这个编辑流程的差价也装好了，可是就是工作不正常。也不知道具体是什么原因。奇怪。 今天偶然发现是xmlBuddy和这个gpd有冲突，想来真是奇怪。不过也不知道Eclipse的工作的原理。只能是先禁用XmlBuddy了。或者说是可以通过怎样的设置使得两者共存？有时间自己去研究一下吧。在网上搜了下，只是看到大家说gpd不正常，我看到他们写的自己的eclipse的配置，都是有xmlbuddy的。自己只是能告诉他们原因是冲突，但是，暂时还是没有solution。谁知道的话也告诉我一下。
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188677#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:15:13 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188677</link>
        <guid>http://vanadies10.javaeye.com/blog/188677</guid>
      </item>
      <item>
        <title>VISTA下的Manifest文件，提升权限</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188676" style="color:red;">http://vanadies10.javaeye.com/blog/188676</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          VISTA下的exe文件如果包含了Manifest文件，并且Manifest文件中指明需要管理员权限，那么会弹出UAC的框让用户确认。下面是这个Manifest文件中关于这个部分的xml代码。<br /><br />&lt;?xml version="1.0" encoding="utf-8"?><br />&lt;assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><br />  &lt;trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"><br />    &lt;security><br />      &lt;requestedPrivileges><br />        &lt;requestedExecutionLevel   level="requireAdministrator"   uiAccess="false" /><br />      &lt;/requestedPrivileges><br />    &lt;/security><br />  &lt;/trustInfo><br />&lt;/assembly>
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188676#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:14:49 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188676</link>
        <guid>http://vanadies10.javaeye.com/blog/188676</guid>
      </item>
      <item>
        <title>VISTA下管理员用户用管理员身份运行程序</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188675" style="color:red;">http://vanadies10.javaeye.com/blog/188675</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          VISTA下，即便你是管理员，也不代表你的程序双击就可以是以管理员身份运行。在4中情况下，是可以按照管理员身份运行的。<br /><br />程序的映像中包含了Vista Manifest文件，并且文件中指名了需要管理员权限 可执行文件被M$认证过，在Vista的数据库中。那么就是可以以管理员权限执行 右键可执行文件，选择以管理员身份执行。 如果文件名是setup或者update。
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188675#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:14:29 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188675</link>
        <guid>http://vanadies10.javaeye.com/blog/188675</guid>
      </item>
      <item>
        <title>编程常犯的错误</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188674" style="color:red;">http://vanadies10.javaeye.com/blog/188674</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          自己写程序也写了不短的日子了。这个blog就列出来自己遇到的常犯的错误吧。也算是给自己一个记录，一个提醒。<br /><br />        集合中的元素的删除。<br /><br />                for(int i=0; i &lt; container.length; i++){<br /><br />                        if(....){<br /><br />                                   container.delete(i);<br /><br />                       }<br /><br />              }<br /><br />            在循环中可能删除多个复合条件的元素。这样的写法就错了。可以改写成<br /><br />                for(int i=container.length; i > 0; i--){<br /><br />                        if(....){<br /><br />                                   container.delete(i--);<br /><br />                       }<br /><br />              }            <br /><br /> <br /><br />             此外就是使用iterator在遍历的时候，直接用容器的delete或者remove方法删除iterator，然后没有跳出循环，继续遍历的话，也是错误的。在java中，可以使用iterator本身的remove。而c++的stl中没有对应的处理办法。如果不使用iterator的remove方法或者不能使用，那么循环中可以考虑如下的写法<br /><br />      for(Iterator iter = container.begin(); iter != container.end(); ){<br /><br />             if(...){<br /><br />                   Iterator tmpIter = iter;<br /><br />                    tmpIter++;<br /><br />                    container.remove(iter);<br /><br />                   iter = tmpIter;<br /><br />            }<br /><br />          else{<br /><br />                iter++;<br /><br />         }<br /><br />      }<br /><br />         C/C++ 中分配内存<br /><br />         void AllocSpace(char *p){<br /><br />                p = new char[1024];<br /><br />         }<br /><br />        p只是一个局部变量，这样的分配只是导致内存泄露。<br /><br />        完成这个意图的写法可以有两种<br /><br />        char * AllocSpace(){<br /><br />                return new char[1024];<br /><br />        }<br /><br />      或者<br /><br />      void AllocSpace(char **p){<br /><br />               *p = new char[1024];<br /><br />        }<br /><br />      <br /><br />    对于delete的误解<br /><br />                char *p = new char[1024];<br /><br />               delete p;<br /><br />              if(NULL != p){<br /><br />             }<br /><br />           delete(free) 只是释放指针指向的内存，并不会使得指针本身的值为NULL
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188674#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:14:10 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188674</link>
        <guid>http://vanadies10.javaeye.com/blog/188674</guid>
      </item>
      <item>
        <title>VISTA中的变化</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188673" style="color:red;">http://vanadies10.javaeye.com/blog/188673</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          无语啊无语。这变化让程序结构都要变化了。<br /><br />Vista Challenge I (session isolation)<br />We spend about 4 months on R&D and final got it working with some support of the MS helpdesk.<br /><br />Vnc and all remote control softwares are having trouble withy the new Vista security model. In de old model, winlogon was always running in the same session as the services, session0<br /><br /><br /><br />While in the new model, the winlogon run in the same session as the desktop.<br /><br /><br /><br />The isolation of the session0, now only used for services, prevent winvnc in service mode to access session X and no interaction with the desktop in session X is possible. Using the service, you can't logon or capture the desktop.<br /><br />Running winvnc in application mode ( started manual in sessionX) all seems to work as long as you don't logoff or use any system application that popup the UAC.<br /><br />Solution I<br />Winvnc need to split exe in a service and a application part. When we run the winvnc_service in session0 and let the service start winvnc_app in the sessionX, winvnc_app can communicate with the desktop and control the mouse and keyboard.<br /><br />An other problem is that sessionX have different desktop, let's take a closer look how desktop exist in Vista. (This model was already partly in use on XP, for the "Fast user switching", remember the black screen you had with VNC after switching user)<br /><br />- Session 0<br /><br />|  |<br /><br />|   ---- WinSta0 (interactive window station)<br /><br />|  |   |<br /><br />|   |  ---- Default (desktop)<br /><br />|  |   |<br /><br />|   |   ---- Disconnect (desktop)<br /><br />|  |   |<br /><br />|   |   ---- Winlogon (desktop)<br /><br />|   |<br /><br />|   ---- winvnc Service (non-interactive window station)<br /><br />|   |   |<br /><br />|   |   ---- Default (desktop)<br /><br />|   |<br /><br />- Session 1<br /><br />|  |<br /><br />|   ---- WinSta0 (interactive window station)<br /><br />|   |   |<br /><br />|   |   ---- Default (desktop)(1**)<br /><br />|   |   |<br /><br />|   |   ---- Disconnect (desktop)<br /><br />|   |   |<br /><br />|   |   ---- Winlogon (desktop)<br /><br />|   |<br /><br />- Session 2<br /><br />| |<br /><br />| ---- WinSta0 (interactive window station)<br /><br />| | |<br /><br />| | ---- Default (desktop) <br /><br />|<br /><br />| | ---- Disconnect (desktop)<br /><br />| |   |<br /><br />| | ---- Winlogon (desktop)  (2**)<br /><br />The service need to check the console desktop and session.<br />If the console desktop is (1**) the service need to start winvnc_app in session1 on the default desktop, the default desktop is the normal desktop where your application run on.<br />If the console desktop is (2**) the service need to start winvnc_app in session2 on the winlogon desktop, this is the secure desktop used to logon.<br />To avoid access problems, you best start the winvnc_app with the same security context as the desktop he is started in.<br />Default Desktop --> user<br />Winlogon Desktop -> local system<br />Createprocessasuser() allow the service to start the exe in the correct security context.<br /><br />This method would be a complete solution to support Fast user switching and access on PC's running RDP. But Vista has other nasty tricks to prevent applications to control a desktop.<br /><br />Vista Challenge II (elevation and UAC)<br />Security elevation <br />From previous MS OS's you know that permissions where based on users. If you logged on as administrator, you could simple click on an executable to start it. As normal user, you needed execute permission on that executable.<br />In Vista applications have a "security elevation".<br />Low: Iexplorere started as administrator runs in low security elevation, this block iexplorer access to many system sources and applications.<br />Normal: A standard application, word pad, run in normal elevation.<br />High: For system utilities, like service manager..<br />The elevation block some interaction from lower elevated application to higher. For Vnc the most important is that sendinput() is blocked. You can't control an application running in higher elevation then the elevation winvnc is running.<br />If you start the service manager from within VNC, VNC mouse clicks get locked by the elevated "service manager" application.<br />If the remote users minimize the "service manager" you have full access again, but remote you are blocked.<br /><br />UAC <br />In older OS version you could simple start a "system application" with a double click, in Vista the UAC jumps in. The UAC popup a "OK" window in the secure desktop, he temporal switch to the winlogon desktop and ask your permission to execute that program.<br />The problem for VNC is that your winvnc_app running in the default desktop has no permission to access the winlogon desktop, remote the whole desktop lock and you need to ask the remote user the press the ok button to continue.<br /><br />Solution II<br />UAC problem can be solved by restarting the winvnc_app in the winlogon desktop, to press OK, and the restarting it again in the default desktop.<br />Great, but now VNC lock because the "system app" has focus and sendinput() is locked because it run in "high" elevation.<br />No problem, should you think, we just add a manifest to the winvnc_app and tell that it need to start in "high" elevation, then it can control all application. ( elevation high has access to all elevation >=high)<br />This works, when you manual click on the winvnc_app.exe, it popup the UAC and you press OK, but when you start it from the service you get a permission denied, CreateprocessAsUser(CPAU) is not allowed to start elevated application......<br /><br />Don't play with the manifest, the only way is to play with the token passed to CPAU and pass the full elevated token, then winvnc_app start elevated and you have access.<br /><br />Vista Challenge II ( Ctrl-alt-del)<br />In previous OS's you could send a message from a service in the winlogon desktop to simulate the CAD sequence...<br />PostMessage(HWND_BROADCAST,WM_HOTKEY,0,MAKELPARAM(MOD_ALT|MOD_CONTROL,VK_DELETE));<br />This does not work in Vista....<br /><br />Solution III<br />We are testing, it has to be possible, the osk (on screen keyboard) can simulate the sequence. The osk use undocumented functions, the "winlogon IPC API"...<br />As workaround, you can use the on screen keyboard. When you press the left/down icon it popup the keyboard and you can that to simulate CAD...<br />Problem solved , Ctrl-Alt-Del can be made with a separate exe "cad.exe"
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188673#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:13:38 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188673</link>
        <guid>http://vanadies10.javaeye.com/blog/188673</guid>
      </item>
      <item>
        <title>Windows Vista 交互式服务编程</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188672" style="color:red;">http://vanadies10.javaeye.com/blog/188672</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Windows Vista 对快速用户切换，用户账户权限，以及服务程序所运行的会话空间都作了很大的改动，致使一些原本可以工作的程序不再能够正常工作了，我们不得不进行一些改进以跟上 Vista 的步伐。<br />我们的软件在Windows NT/2000/XP/Vista 系统中安装了一个系统服务，这个服务负责以 SYSTEM 权限启动我们的主程序。我们的主程序启动后会在系统托盘添加一个图标，点击此图标可以弹出控制菜单，通过这个菜单也可以激活配置程序首选项的对话框。在 Windows NT/2000/XP 下我们的程序都可以正常工作。哦不，当 XP 具备了快速用户切换功能的时候我们的问题已经出现了。XP 启动后我们以用户 A 登录，我们的图标出现在系统托盘，一切工作都正常，可当我们使用快速用户切换，切换到用户B后（用户A此时也是已登录状态，并没有注销），虽然用户B已经是本地控制台会话(Session 属性为 Console)但我们的图标已经无法出现了，自然菜单和对话框更无从谈起了。我们的程序是和本机控制台桌面相关的，这种情况无疑是个缺陷。再来看一下在 Vista 平台是怎么样吧，系统启动后以用户A登录，我们的图标更本就没有出现，查看进程管理器中的进程列表发现我们的程序已经启动了，当我们从远端检查我们的服务，发现已经正常工作，尝试远程登录我们的服务，Vista 会在本机控制台弹出一个消息框，提示有交互式服务消息，是否查看这个消息，点击立刻查看发现切换到另外一个桌面去了。<br />于是开始分析这种情况发生的原因。在 Windows NT/2000 中系统服务进程和本机控制台交互式登录的用户都运行于Session0 中，默认用户桌面运行于 WinSta0 窗口站，所以我们的程序由服务程序启动时依然是和本机用户处于同一个Session中，即使在某些情况下出现不能弹出对话框或者无法添加系统托盘图标的情况也只需要修改一下进程桌面到 WinSta0\Default 就可以了（可以参考 MSDN 中 OpenInputDesktop, SetThreadDesktop 等API的说明）。<br />XP为我们带来了快速用户切换，也让我们所采用的软件架构问题浮现出来。当我们快速切换到用户B的时候，用户A仍然在会话中(Session0)，而用户B则处于新启动的会话中(Session1或者其他)，此时服务程序和本机控制台程序就不在处于同一会话了，OpenInputDesktop,SetThreadDesktop 等API的工作范围仅限于本Session，用户A没有退出，Session0也依然存在但是已经是 Disconnected 状态，当进程所处的Session是 Disconnected 状态的时候调用 OpenInputDesktop 会返回错误“无效的API”。进程及线程所属的Session 是由他们的Token 结构中的 TokenSessionId 决定的（参见MSDN中SetTokenInformation 和 TOKEN_INFORMATION_CLASS的说明），我尝试以微软提供的相关API修改运行中的进程和线程的TokenSessionId 信息从而达到修改桌面环境的目的，到目前还没有成功过（或许可以尝试参考RootKit 技术，不过即使修改成功到底能不能实现我们的需求也不确定）。我们的进程无法跨越Session的界限，自然无法与当前活动的另外一个Session中的桌面交互了，L 。<br />Vista中又是如何的一番景象呢？处于安全方面及其他因素的考虑，Vista以及将所有的服务程序置于Session0中，而为本机第一个交互登录的用户创建了Session1，快速切换到用户B后则是 Session2，无论是本机登录的用户，快速切换后的用户，还是远程桌面登录的用户再也没有谁和服务进程处于同一个Session中了，我们的程序还运行在Session0中，自然我们的托盘图标是没有用户能看到了。事实上这个图标还是可以出现的。Session0因为不是一个交互式会话所以没有象其他用户环境初始化的时候一样启动Explorer程序，但是我们开始可以手工启动他，在Session0中启动 Explorer 后任务栏出现后我们还是看到了我们的图标（具体启动Explorer的方法我们不在此文中讨论），菜单、对话框也可以使用。<br />既然我们的程序必须运行在Session0而我们又没有办法把我们的图标、对话框一下子就抛到隔壁Session的用户桌面上去，只能想其他的办法了。微软也不提倡我们这种服务程序直接提供GUI与用户直接交互的方式，而他们建议使用C/S架构，Client/Server之间用Socket/Pipe/RPC等方式通讯，这样我们只要把Client整个进程放到用户Session去和用户交互，然后将配置信息等内容通过上述途径传递给Server，服务端在作出相应的响应即可。<br />把GUI分离出来并不是那么困难，然后在以前直接调用的地方加上一个通过Pipe通讯的接口，这样GUI(Client)的运行就可以灵活的掌握了。<br />最初我想把用户界面程序放到 Startup（启动）中随用户登录自动启动。这样当用户A和B都登录后将有两个用户界面程序在运行，而我们的服务只是和当前活动的控制台登录用户交互，所以这样并不符合需求。<br />接下来我们需要看看如何判定当前的活动Session是哪个，然后如何在这个活动Session中启动我们的用户界面程序了。<br />微软从XP/2003开始为我们提供了一套Windows Terminal Service 的相关API，这些API都以WTS开头（请安装MSDN2005以查阅相关说明），要获得活动Session也不止一个途径，最简单的就是直接使用<br />DWORD WTSGetActiveConsoleSessionId(void);<br />来获得活动Session Id 。要在程序中使用这些API需要最新的Platform SDK（如果你正在使用Visual Studio 2005那么它已经具备了相关头文件和库文件可以直接使用了），如果你在使用VC++ 6.0 你也没有或者不打算安装最新的SDK那么你可以直接使用LoadLibrary() 装载wtsapi32.dll然后使用GetProcAddress()获得相关函数的地址以调用它们。我们获得了活动SessionId后就可以使用<br />BOOL WTSQueryUserToken(<br /> ULONG SessionId,<br /> PHANDLE phToken<br />);<br />来获取当前活动Session中的用户令牌(Token)，有了这个Token我们的就可以在活动Session中创建新进程了，<br />BOOL CreateProcessAsUser(<br /> HANDLE hToken,<br /> LPCTSTR lpApplicationName,<br /> LPTSTR lpCommandLine,<br /> LPSECURITY_ATTRIBUTES lpProcessAttributes,<br /> LPSECURITY_ATTRIBUTES lpThreadAttributes,<br /> BOOL bInheritHandles,<br /> DWORD dwCreationFlags,<br /> LPVOID lpEnvironment,<br /> LPCTSTR lpCurrentDirectory,<br /> LPSTARTUPINFO lpStartupInfo,<br /> LPPROCESS_INFORMATION lpProcessInformation<br />);<br />将我们获得的Token作为此API的第一个参数即可，你可以先尝试一下运行一个notepad.exe看看，怎么样？你可以在控制台桌面上看到新进程了。再查看一下进程列表，该进程的用户名是当前控制台登录的用户。可是这里我们又遇到一个问题，我们需要收集当前交本机互式登录用户的一些信息，而有些操作需要很高的权限才能完成，而Vista下即使是Administraotrs用户组成员默认也是以Users权限启动进程的，所以我们创建的新进程只有Users权限，无法完成一些操作，当然我们可以使用Vista所提供的UI来询问用户以提升至管理员权限，可有些操作甚至是管理员Token也无法完成的，而且需要用户确认实在在易用性上大打折扣，所以我决定在活动Session中以SYSTEM权限启动我们的用户交互程序。显然 WTSQueryUserToken() 是不好用了。<br />之前，我们提到过进程所属的Session是由进程Token中的TokenSessionId来决定的，那么我们是不是可以复制服务进程的Token然后修改其中的TokenSessionId，从而在用户桌面上创建一个具有SYSTEM权限的新进程呢？答案是肯定的。一下是实现这个操作的代码，为了缩小篇幅我删除了异常处理代码<br />HANDLEhTokenThis = NULL;<br />HANDLEhTokenDup = NULL;<br />HANDLEhThisProcess = GetCurrentProcess();<br />OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);<br />DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);<br />DWORDdwSessionId = WTSGetActiveConsoleSessionId();<br />SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD));<br /> <br />STARTUPINFOsi;<br />PROCESS_INFORMATION pi;<br />ZeroMemory(&si, sizeof(STARTUPINFO));<br />ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));<br />si.cb = sizeof(STARTUPINFO);<br />si.lpDesktop = "WinSta0\\Default";<br /> <br />LPVOIDpEnv = NULL;<br />DWORDdwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;<br /> <br />CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE);<br /> <br />CreateProcessAsUser(<br />              hTokenDup,<br />              NULL,<br />              (char *)"notepad", <br />              NULL,<br />              NULL,<br />              FALSE,<br />              dwCreationFlag,<br />              pEnv,<br />              NULL,<br />              &si,<br />              &pi);<br />  <br /><br /> <br />到这里我们的大部分工作已经完成了，我们还需要做的就是监控活动Session的变化，就是用户的登录、注销、快速切换。WTS系列API以及为我们提供了具备这些能力的API了，大致可以用一下几种方法实现:<br />1.              设置一个定时器，使用WTSGetActiveConsoleSessionId()轮询活动桌面id，当检测到变化的时候让用户交互程序的前一个实例退出，在新活动Session中创建新进程。<br />2.              使用WTSRegisterSessionNotification()函数注册一个窗口来接收WTSSESSION_NOTIFICATION消息，来判断Session变化。<br />3.              使用 WTSEnumerateSessions枚举所有Session然后根据返回的WTS_SESSION_INFO结构中的State成员来判断Session状态，找到处于 Active状态的Session.<br />结合你的其他需求选择其中之一，然后作出响应就可以了。
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188672#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:12:57 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188672</link>
        <guid>http://vanadies10.javaeye.com/blog/188672</guid>
      </item>
      <item>
        <title>Services isolation in Session 0 of Windows Vista a</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188671" style="color:red;">http://vanadies10.javaeye.com/blog/188671</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          看到一篇不错的文章。转载过来也算是给自己的一个积累吧。<br /><br />You may have heard that built-in services in Windows Vista were specifically hardened by Microsoft engineers during its development process. You might be wondering what that really means, how it works and, if you are a developer, how to harden your own services the Vista way.  Jean-Yves Poublan, a Principal Security Consultant at Microsoft, and I are publishing a series of posts on how to leverage Windows Vista new architecture to make your services more secure. <br />Today, we start with a significant change with Windows Vista and Longhorn Server: Win32 services are now isolated in Session 0. So, what does this mean for developers?<br /> <br />‘windows’ on ‘desktops’ in ‘window stations’ in ‘Terminal Services sessions’<br />Windows NT was designed to be a multi-user system through the use of sessions. The SDK refers to these as Terminal Services sessions which are not to be confused with logon sessions, as they are not the same thing. Terminal Services sessions are created and managed by the session manager (smss.exe) which is one of the first processes created when the system starts. Logon sessions and processes somehow live within a Terminal Services session. <br />Note : The Terminal Services session ID for a given logon session may be obtained by calling the LsaGetLogonSessionData API after having enumerated the logon sessions (LsaEnumerateLogonSessions). One may also get the Terminal Services session ID for a process with the GetTokenInformation(TokenSessionId) API after having obtained the primary token for the process (OpenProcessToken).<br />Previous to Windows Vista and Longhorn Server, Win32 services and user applications for the console user (as well as winlogon.exe and the Win32 subsystem – csrss.exe) were all started within Terminal Services Session 0. A second Terminal Services session (Session 1) was created when a second user logged on (such as a user connecting through Terminal Services on Windows Server 2003, or a second user logging on Windows XP through Fast User Switching), and so on.<br />So user applications for the console user always shared Session 0 with system services. This is no longer the case with Windows Vista and Longhorn server. <br />What is wrong with having system services and user applications live in the same session? Well, it mostly has to do with interactive services. <br />First let’s recall what desktops and window stations are. Both are securable kernel objects in the sense that they are protected by ACLs. You can think of Terminal Services sessions having window stations that in turn contain desktops. There is a special window station called Winsta0 which is the windows station that is connected to the display and input devices. Processes are attached to a window station which they are going to use (supposedly) to interact with the user. Threads within a process are themselves attached to a desktop (within the window station) on which they display windows and they get input from the user. Windows messages are confined within a desktop, and Winsta0 will typically have three desktops: the winlogon desktop, the interactive desktop, and the screen saver desktop. Winsta0 grants rights to SYSTEM and the logon SID, so only the system and the currently logged on user can access the console. When a user logs off, the logon SID is removed from Winsta0, and when a new user logs on, the new logon SID is added to Winsta0’s ACL.<br />Windows, on the other hand, are user objects that are not securable by ACLs. So threads that have gained access to a desktop can send messages to any window on that desktop. In the past, applications that ran with higher privileges on the desktop have been vulnerable to the infamous shatter attacks from other malicious applications.<br />Normally, Win32 services are not attached to Winsta0 (they don’t have the rights on Winsta0), but instead they get their own window stations. Those window stations are not connected to any hardware so if a service displays a window and waits for user input, it may well wait forever…<br /> <br />Interactive services – to be avoided if at all possible<br />Interactive services are services that are configured as such (flag SERVICE_INTERACTIVE_PROCESS for CreateService or ChangeServiceConfig APIs). When the SCM starts a process for an interactive service, it attaches the service to Winsta0 instead of the service window station. In order to do so, the service process must run as SYSTEM (since only SYSTEM - and currently logged on user - have rights on Winsta0). Service threads can then attach to the interactive desktop and interact with the user.<br />One can see two compounded problems here: interactive services are vulnerable to Windows messages attacks from malicious user applications, and those attacks can result in privilege elevation since interactive services run as SYSTEM with TCB privilege. So deploying an interactive service that is vulnerable could compromise the whole system.<br />There are other things wrong with interactive services. On Windows Server 2003 with Terminal Services, the user that is currently logged on at the console in Session 0 may not be the user that the service should interact with. On Windows XP with Fast User Switching, it is even worse. The currently active console user may not be Session 0, but Session 1 (or Session n). In that case, if the interactive service waits for user input, it may wait forever from Session 0 which is not active. It is said that interactive services with Fast User Switching just don’t work. Because of that, developing and deploying interactive services has been strongly discouraged. As a matter of fact, interactive services can be banned from the system by setting the NoInteractiveServices registry value to 1 in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows. In that case, interactive services will still be started by the SCM (Services Control Manager), but they won’t be attached to Winsta0 (the SCM does log a warning in the event log). This is valid for Windows Vista and Longhorn as well.<br /> <br />Isolation of services in Session 0 with Windows Vista and Longhorn Server<br />With Windows Vista and Longhorn Server, user applications for the first logged on console user are now started in Terminal Services Session 1, and services in Session 0 are isolated from user applications. The second logged on user gets Session 2 and so on. Services isolation in Session 0 helps protecting the system from malicious user applications. Imagine one has installed an interactive service that is vulnerable, that interactive service will not share the desktop with (potentially) malicious user applications anymore and as such will be less likely to be compromised and used as a vehicle to attack the system.<br />Services isolation in Session 0 affects all services that assume they are running in the same session as user applications, and not only services that configured as interactive services. For instance, a service that communicates with user applications by way of Windows messages will no longer work. Also, a service that synchronizes with user applications through synchronization objects (semaphores, mutexes, etc…) created in the session private name space will no longer work as well. The global name space should be used instead (object names prefixed with Global\).<br />Under Windows Vista and Longhorn, a service can still be configured to be an interactive service, but such configuration does not make a whole lot of sense, since the interactive service will be attached to the Winsta0 in Session 0, which does not have a physical console and user to interact with.<br /> If you have a service that is designed to be an interactive service and as such interacts with the desktop, or a service that assumes it is running in the same session as user applications, it is time to change it. Windows SDK does give some ideas of how a service could interact with users, without having to be an interactive service. This includes communicating with a user process through some form of IPC (preferably secure) channel, or using Terminal Services APIs such WTSSendMessage. Determining which user (in which target session) your service should interact with is up to you but should not be overlooked.<br />For legacy interactive services that cannot be changed in the short term, Windows Vista provides a compatibility mechanism called Interactive Service Detection service (ui0detect.exe). UI0Detect monitors interactive services in Wintsta0 of Session 0 and when such service displays a modal dialog it notifies the user in the currently active console session. The user can choose to switch to Winsta0/interactive desktop of Session 0 to respond to the dialog, and then switch back to the user session. UI0Detect is a temporary measure designed to limit the effect of Session 0 service isolation for existing interactive services that cannot be changed. As a service developer you should not count on that mechanism.<br /> <br />What about MessageBox() and MessageBox(MB_SERVICE_NOTIFICATION)?<br />When calling the MessageBox() API - *without* the MS_SERVICE_NOTIFICATION flag - from a service that is not an interactive service, the thread waits forever. It is worth noting that if a non interactive service is programmed in managed code on the .Net Runtime, calling the System.Windows.Forms.MessageBox.Show() method will raise an exception (“System.InvalidOperationException: Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application”) instead of hanging there waiting for user input. Also if the service is an interactive service, under Windows Vista, UI0Detect will handle the interaction for MessageBox() – without MB_SERVICE_NOTIFICATION.<br />The MB_SERVICE_NOTIFICATION flag causes the system to redirect the message box to the interactive desktop (or winlogon desktop if there is no user logged on) on WinSta0 where it is handled by csrss.exe (the Win32 subsystem).It was designed to allow services that technically are not interactive services (i.e. they are not configured as interactive services and thus are not attached to Winsta0) to display a modal dialog message box on the interactive desktop and get user input. <br />Under Windows Vista RTM, this does not work however, in the sense that instead of the message box being redirected to the interactive desktop of a session with a user on it, or taken care of by UI0Detect as one could hope, the functions returns IDOK immediately with no user interaction whatsoever. It behaves that way even for services that are configured as interactive services and whose interactions are normally handled by UI0Detect. If your service uses MessageBox(MB_SERVICE_NOTIFICATION) to ask for user approval for some operation, it may need to be modified.<br />The following two tables summarize MessageBox behaviors under Windows XP SP2 and Windows Vista RTM.<br />NoInteractiveServices = 0 NoInteractiveServices = 1 <br />SERVICE_INTERACTIVE_PROCESS<br />(CreateService, ChangeServiceConfig) <br />Window station (service is running as SYSTEM) 0x00000000<br />"Allow service to interact with desktop"= unchecked <br />Service-0x0-3e7$  0x00000100<br />"Allow service to interact with desktop"= checked <br />WinSta0  0x00000000<br />"Allow service to interact with desktop"= unchecked <br />Service-0x0-3e7$ 0x00000100<br />"Allow service to interact with desktop"= checked <br />Service-0x0-3e7$ <br />MessageBox()  No display – waiting forever (1)  Display OK (directly by service process)<br /><br /> No display – waiting forever (1) SCM warning in event log when starting the service <br />No display – waiting forever (1) <br />MessageBox(MB_SERVICE_NOTIFICATION)  Display OK (through csrss.exe)  Display OK (through csrss.exe) Display OK (through csrss.exe) SCM warning in event log when starting the service <br />Display OK (through csrss.exe) <br /><br /><br />MessageBox behavior on Windows XP SP2<br />(1) Managed code: runtime will raise an exception<br /> <br />NoInteractiveServices = 0 NoInteractiveServices = 1 <br />SERVICE_INTERACTIVE_PROCESS<br />(CreateService, ChangeServiceConfig) <br />Window station (service is running as SYSTEM) 0x00000000<br />"Allow service to interact with desktop"= unchecked <br />Service-0x0-3e7$  0x00000100<br />"Allow service to interact with desktop"= checked <br />WinSta0  0x00000000<br />"Allow service to interact with desktop"= unchecked <br />Service-0x0-3e7$ 0x00000100<br />"Allow service to interact with desktop"= checked <br />Service-0x0-3e7$ <br />MessageBox()  No display – waiting forever (1) Interactive Service Detection – user can switch to Session 0 to respond service  No display – waiting forever (1) SCM warning in event log when starting the service <br />No display – waiting forever (1) <br />MessageBox(MB_SERVICE_NOTIFICATION)  No display – returns 1 (IDOK)(2) immediately  No display – returns 1 (IDOK)(2) immediately No display – returns 1 (IDOK)(2) immediately SCM warning in event log when starting the service <br />No display – returns 1 (IDOK)(2) immediately <br /><br /><br />MessageBox behavior on Windows Vista RTM<br />(1) Managed code: runtime will raise an exception<br />(2) Even if message box has no such button
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188671#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:12:15 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188671</link>
        <guid>http://vanadies10.javaeye.com/blog/188671</guid>
      </item>
      <item>
        <title>JDK 6.0 新特性</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188670" style="color:red;">http://vanadies10.javaeye.com/blog/188670</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          JDK6.0发布有段时间了，新的JDK也有不少新的特性，我去网上搜集了一下，列在下面和大家一起学习．<br />１．Desktop和SystemTray. 在JDK6中 ,AWT新增加了两个类:Desktop和SystemTray,前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托盘程序。<br /><br />我随便找了几张图，在Tray里面都是空的，没有图,可能是图太大，有xdjm知道希望告诉我．<br /><br /><br />import java.awt.AWTException;<br />import java.awt.Desktop;<br />import java.awt.Image;<br />import java.awt.MenuItem;<br />import java.awt.PopupMenu;<br />import java.awt.SystemTray;<br />import java.awt.Toolkit;<br />import java.awt.TrayIcon;<br />import java.awt.event.ActionEvent;<br />import java.awt.event.ActionListener;<br />import java.io.File;<br />import java.io.IOException;<br />import java.net.URI;<br />import java.net.URISyntaxException;<br /><br />public class DesktopTrayTest ...{<br />    private static Desktop desktop;<br />    private static SystemTray st;<br />    private static PopupMenu pm;<br />    <br />    public static void main( String[] args ) ...{<br />        if( Desktop.isDesktopSupported() ) ...{<br />            desktop = Desktop.getDesktop();<br />        }<br />        if( SystemTray.isSupported() ) ...{<br />            st = SystemTray.getSystemTray();<br />            Image image = Toolkit.getDefaultToolkit().createImage( "http://www.51ppt.com.cn/Article/Uploadphotos/200604/20064147333288.png" );<br />            createPopupMenu();<br />            TrayIcon ti = new TrayIcon( image, "Demo", pm );<br />            try...{<br />                st.add( ti );<br />            } catch( AWTException awte ) ...{<br />                awte.printStackTrace();<br />            }<br />        }<br />    }<br />    public static void sendMail( String mail ) ...{<br />        if( desktop != null &&<br />            desktop.isSupported( Desktop.Action.MAIL ) ) ...{<br />            try ...{<br />                desktop.mail( new URI( mail ) );<br />            } catch (IOException e) ...{<br />                e.printStackTrace();<br />            } catch (URISyntaxException e) ...{<br />                e.printStackTrace();<br />            }<br />        }<br />    }<br />    public static void openBrowser( String url ) ...{<br />        if( desktop != null &&<br />            desktop.isSupported( Desktop.Action.BROWSE )) ...{<br />            try ...{<br />                desktop.browse( new URI( url ) );<br />            } catch (IOException e) ...{<br />                e.printStackTrace();<br />            } catch (URISyntaxException e) ...{<br />                e.printStackTrace();<br />            }<br />        }<br />    }<br />    public static void edit() ...{<br />        if( desktop != null &&<br />            desktop.isSupported( Desktop.Action.EDIT ) ) ...{<br />            File file = new File( "test.txt" );<br />            try ...{<br />                if( file.exists() == false ) ...{<br />                    file.create();<br />                }<br />                desktop.edit( file );<br />            } catch( IOException ioe ) ...{<br />                ioe.printStackTrace();<br />            }<br />        }<br />    }<br />    public static void createPopupMenu() ...{<br />        pm = new PopupMenu();<br />        MenuItem ob = new MenuItem( "Open url" );<br />        ob.addActionListener( new ActionListener() ...{<br />            public void actionPerformed( ActionEvent ae ) ...{<br />                openBrowser( "http://blog.csdn.net/xumingming64398966" );<br />            }<br />        });<br />        MenuItem sm = new MenuItem( "Send Mail" );<br />        sm.addActionListener( new ActionListener() ...{<br />            public void actionPerformed( ActionEvent ae ) ...{<br />                sendMail( "64398966@qq.com" );<br />            }<br />        });<br />        MenuItem ed = new MenuItem( "Edit" );<br />        ed.addActionListener( new ActionListener() ...{<br />            public void actionPerformed( ActionEvent ae ) ...{<br />                edit();<br />            }<br />        });<br />        MenuItem ex = new MenuItem( "Exit" );<br />        ex.addActionListener( new ActionListener() ...{<br />            public void actionPerformed( ActionEvent ae ) ...{<br />                System.exit( 0 );<br />            }<br />        });<br />        pm.add( ob );<br />        pm.add( sm );<br />        pm.add( ed );<br />        pm.addSeparator();<br />        pm.add( ex );<br />    }<br />}<br /><br /> <br /><br />２．Console. JDK6中提供了java.io.Console类专用来访问基于字符的控制台设备. 你的程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳. 但我们不总是能得到可用的Console, 一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用. 如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例. 下面代码演示了Console类的用法: <br /><br /><br />import java.io.Console;<br /><br />public class ConsoleTest ...{<br />    public static void main( String[] args ) ...{<br />        Console console = System.console();<br />        if( console != null ) ...{<br />            String user = new String( console.readLine( "Enter User:", new Object[ 0 ] ) );<br />            String pwd = new String( console.readPassword( "Enter Password:", new Object[ 0 ] ));<br />            console.printf( "User name is:%s", new Object[]...{user} );<br />            console.printf( "Password is:%s", new Object[]...{pwd} );<br />        } else ...{<br />            System.out.println( "No Console!" );<br />        }<br />    }<br />}<br /><br /><br />你如果是在一个IDE中如eclipse, netbeans中运行你将得到：<br />No Console!<br />因为只有在命令行中才能得到Console对象。<br /><br />３．Compiler API. 现在我们可以用JDK6 的Compiler API(JSR 199)去动态编译Java源文件，Compiler API结合反射功能就可以实现动态的产生Java代码并编译执行这些代码，有点动态语言的特征。这个特性对于某些需要用到动态编译的应用程序相当有用，比如JSP Web Server，当我们手动修改JSP后，是不希望需要重启Web Server才可以看到效果的，这时候我们就可以用Compiler API来实现动态编译JSP文件，当然，现在的JSP Web Server也是支持JSP热部署的，现在的JSP Web Server通过在运行期间通过Runtime.exec或ProcessBuilder来调用javac来编译代码，这种方式需要我们产生另一个进程去做编译工作，不够优雅而且容易使代码依赖与特定的操作系统；Compiler API通过一套易用的标准的API提供了更加丰富的方式去做动态编译,而且是跨平台的。 下面代码演示了Compiler API的使用：<br /><br /><br />import java.io.BufferedWriter;<br />import java.io.FileWriter;<br />import java.io.IOException;<br />import java.util.Iterator;<br /><br />import javax.tools.JavaCompiler;<br />import javax.tools.JavaFileObject;<br />import javax.tools.StandardJavaFileManager;<br />import javax.tools.ToolProvider;<br /><br />public class CompilerAPITest ...{<br />    private final static String srcFileName = "Test.java";<br />    private final static String classFileName = "Test.class";<br />    private final static String className = "Test";<br />    <br />    public static void main( String[] args ) ...{<br />        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();<br />        if( compiler == null ) ...{<br />            System.err.println( "Compiler is null!" );<br />            return;<br />        }<br />        StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );<br />        generateJavaClass();<br />        <br />        Iterable &lt; ? extends JavaFileObject> sourceFiles = fileManager.getJavaFileObjects( new String[]...{ srcFileName } );<br />        compiler.getTask( null, fileManager, null, null, null, sourceFiles ).call();<br />        try ...{<br />            fileManager.close();<br />            Class.forName( className ).newInstance();<br />        } catch (IOException e) ...{<br />            e.printStackTrace();<br />        } catch (InstantiationException e) ...{<br />            e.printStackTrace();<br />        } catch (IllegalAccessException e) ...{<br />            e.printStackTrace();<br />        } catch (ClassNotFoundException e) ...{<br />            e.printStackTrace();<br />        }<br />    }<br />    <br />    public static void generateJavaClass() ...{<br />        try ...{<br />            FileWriter rw = new FileWriter( srcFileName );<br />            BufferedWriter bw = new BufferedWriter( rw );<br />            bw.write( "public class " + className + " {" );<br />            bw.newLine();<br />            <br />            bw.write( "public " + className + "() {");<br />            bw.newLine();<br />            bw.write( "System.out.println( 'you are in the constructor of Class Test' );" );<br />            bw.write( "}" );<br />            bw.newLine();<br />            <br />            bw.write( "}" );<br />            bw.flush();<br />            bw.close();<br />        } catch (IOException e) ...{<br />            e.printStackTrace();<br />        }<br />    }<br />}<br /><br />我在运行这个例子的时候发现ToolProvider.getSystemJavaCompiler得到的是NULL,后来上网一查，原来是一个Bug!链接如下：<br />http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6477844<br /><br />Closed, not reproducible<br />那为什么我一直在reproduce阿？ <br /><br />4.Http Server API. JDK6提供了一个简单的Http Server API,据此我们可以构建自己的嵌入式Http Server,它支持Http和Https协议,提供了HTTP1.1的部分实现，没有被实现的那部分可以通过扩展已有的Http Server API来实现,程序员必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给 HttpHandler实现类的回调方法.下面代码演示了怎样创建自己的Http Server .<br /><br /> <br /><br />import java.io.IOException;<br />import java.io.InputStream;<br />import java.io.OutputStream;<br />import java.net.InetSocketAddress;<br /><br />import com.sun.net.httpserver.HttpExchange;<br />import com.sun.net.httpserver.HttpHandler;<br />import com.sun.net.httpserver.HttpServer;<br /><br />public class HttpServerAPITest ...{<br />    private static int count = 0;<br />    public static void main( String[] args ) ...{<br />        try ...{<br />            HttpServer hs = HttpServer.create( new InetSocketAddress( 8888 ), 0 );<br />            hs.createContext( "/", new MyHandler() );<br />            hs.createContext( "/java", new MyHandler() );<br />            hs.setExecutor( null );<br />            hs.start();<br />            System.out.println( "---begin---" );<br />            System.out.println( "Listening on " + hs.getAddress() );<br />        } catch( IOException ioe ) ...{<br />            ioe.printStackTrace();<br />        }<br />    }<br />    static class MyHandler implements HttpHandler ...{<br />        public void handle( HttpExchange he ) throws IOException ...{<br />            System.out.println( "Request " + count++  );<br />            System.out.println( he.getHttpContext().getPath() );<br />            <br />            InputStream is = he.getRequestBody();<br />            String response = "&lt;font color='blue'>Happy Spring Festerval&lt;/font>";<br />            he.sendResponseHeaders( 200, response.length() );<br />            OutputStream os = he.getResponseBody();<br />            os.write( response.getBytes() );<br />            os.close();<br />        }<br />    }<br />}<br /><br /> <br /><br />效果如图:<br /><br /> <br /><br />5.对脚本语言的支持如: ruby, groovy, javascript.<br /><br />代码如下:<br /><br />import java.io.FileReader;<br /><br />import javax.script.Invocable;<br />import javax.script.ScriptEngine;<br />import javax.script.ScriptEngineManager;<br /><br />public class ScriptTest ...{<br />    public static void main( String[] args ) ...{<br />        ScriptEngineManager manager = new ScriptEngineManager();<br />        ScriptEngine engine = manager.getEngineByName( "ECMAScript" );<br />        try ...{<br />            engine.eval( new FileReader( "C:\test.js" ) );<br />            Invocable invocableEngine = (Invocable)engine;<br />            Object ret = invocableEngine.invokeFunction( "test", null );<br />            System.out.println( "The result is :" + (Double)ret );<br />        } catch( Exception e ) ...{<br />            e.printStackTrace();<br />        }<br />    }<br />}<br /><br />test.js如下:<br /><br />function test()...{<br />    return Math.round( 11.2 );<br />}<br />6.插入式注解处理API(Pluggable Annotation Processing API)，插入式注解处理API(JSR 269)提供一套标准API来处理Annotations.JSR 269用Annotation Processor在编译期间而不是运行期间处理Annotation, Annotation Processor相当于编译器的一个插件,所以称为插入式注解处理.如果Annotation Processor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次Annotation Processor,如果第二次处理还有新代码产生,就会接着调用Annotation Processor,直到没有新代码产生为止.每执行一次process()方法被称为一个"round",这样整个Annotation processing过程可以看作是一个round的序列. <br />举个例子：们想建立一套基于Annotation的单元测试框架(如TestNG),在测试类里面用Annotation来标识测试期间需要执行的测试方法,如下所示:<br /><br /><br />@TestMethod<br /> public void testCheckName()...{<br />       //do something here<br /> }<br /><br />这时我们就可以用JSR 269提供的API来处理测试类,根据Annotation提取出需要执行的测试方法. <br /><br /><br />再举个例子: 下面我用代码演示如何来用JSR 269提供的API来处理Annotations和读取Java源文件的元数据(metadata)<br /><br /><br />import java.util.List;<br />import java.util.Map;<br />import java.util.Set;<br /><br />import javax.annotation.processing.AbstractProcessor;<br />import javax.annotation.processing.RoundEnvironment;<br />import javax.annotation.processing.SupportedAnnotationTypes;<br />import javax.annotation.processing.SupportedSourceVersion;<br />import javax.lang.model.SourceVersion;<br />import javax.lang.model.element.AnnotationMirror;<br />import javax.lang.model.element.AnnotationValue;<br />import javax.lang.model.element.Element;<br />import javax.lang.model.element.ExecutableElement;<br />import javax.lang.model.element.TypeElement;<br />import javax.lang.model.util.ElementFilter;<br />import javax.tools.Diagnostic.Kind;<br /><br />@SupportedAnnotationTypes( "ToBeTested" )<br />@SupportedSourceVersion( SourceVersion.RELEASE_6 )<br />public class MyAnnotationProcessor extends AbstractProcessor ...{<br />    private void note( String msg ) ...{<br />        processingEnv.getMessager().printMessage( Kind.NOTE, msg );<br />    }<br />    public boolean process( Set&lt; ? extends TypeElement > annotations, RoundEnvironment roundEnv ) ...{<br />        for( TypeElement te : annotations ) ...{<br />            note( "annotation: " + te.toString() );<br />        }<br />        Set&lt; ? extends Element > elements = roundEnv.getRootElements();<br />        for( Element e : elements ) ...{<br />            List&lt; ? extends Element > enclosedElems = e.getEnclosedElements();<br />            List&lt; ? extends ExecutableElement > ees = ElementFilter.methodsIn( enclosedElems );<br />            for( ExecutableElement ee : ees ) ...{<br />                note( "Executable Element Name: " + ee.getSimpleName() );<br />                List&lt; ? extends AnnotationMirror > as = ee.getAnnotationMirrors();<br />                note( " as: " + as ); <br />                for( AnnotationMirror am : as )...{<br />                    Map&lt; ? extends ExecutableElement, ? extends AnnotationValue > map = am.getElementValues();<br />                    Set&lt; ? extends ExecutableElement > ks = map.keySet();<br />                    for( ExecutableElement k : ks ) ...{<br />                        AnnotationValue av = map.get( k );<br />                        note("----"+ee.getSimpleName()+"."+k.getSimpleName()+"="+av.getValue());<br />                    }<br />                }<br />            }<br />        }<br />        return false;<br />    }<br />}<br /><br /> <br /><br /><br />public class Testing ...{<br />    @ToBeTested(group="A")<br />    public void m1()...{<br />    }<br />    @ToBeTested(group="B",owner="QQ")<br />    public void m2()...{<br />    }    <br />}<br /><br /> <br /><br />import java.lang.annotation.ElementType;<br />import java.lang.annotation.Retention;<br />import java.lang.annotation.RetentionPolicy;<br />import java.lang.annotation.Target;<br /><br />@Retention( RetentionPolicy.RUNTIME )<br />@Target( ElementType.METHOD )<br />public @interface ToBeTested ...{<br />    String owner() default "Chinajash";<br />    String group();<br />}<br /><br />效果如下：<br /><br /><br />7.SAX. SAX是The Streaming API for XML的缩写，是继DOM(Document Object Model)和SAX(Simple API for XML)之后的又一种处理xml的api,一种利用拉模式解析(pull-parsing)XML文档的API.SAX通过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每一个解析事件，解析事件可以看做是程序拉出来的，也就是程序促使解析器产生一个解析事件然后处理该事件，之后又促使解析器产生下一个解析事件，如此循环直到碰到文档结束符；SAX也是基于事件处理xml文档，但却是用推模式解析，解析器解析完整个xml文档后，才产生解析事件，然后推给程序去处理这些事件；DOM采用的方式是将整个xml文档映射到一颗内存树，这样就可以很容易地得到父节点和子结点以及兄弟节点的数据，但如果文档很大，将会严重影响性能。<br /><br />下面是个例子：<br /><br /> <br /><br />import java.io.FileNotFoundException;<br />import java.io.FileOutputStream;<br /><br />import javax.xml.namespace.QName;<br />import javax.xml.stream.XMLEventReader;<br />import javax.xml.stream.XMLInputFactory;<br />import javax.xml.stream.XMLOutputFactory;<br />import javax.xml.stream.XMLStreamException;<br />import javax.xml.stream.XMLStreamWriter;<br />import javax.xml.stream.events.StartElement;<br />import javax.xml.stream.events.XMLEvent;<br /><br />public class SaxTest ...{<br />    public static void main( String[] arg ) throws XMLStreamException, FileNotFoundException ...{<br />        readXMLBySAX();<br />        writeXMLBySAX();<br />    }<br />    public static void readXMLBySAX() throws XMLStreamException, FileNotFoundException ...{<br />        XMLInputFactory factory = XMLInputFactory.newInstance();<br />        XMLEventReader  reader = factory.createXMLEventReader( SaxTest.class.getResourceAsStream( "test.xml" ) );<br />        XMLEvent event;<br />        StringBuffer  parsingResult = new StringBuffer();<br />        while( reader.hasNext() ) ...{<br />            event = reader.nextEvent();<br />            if( event.isStartElement() ) ...{<br />                StartElement se = event.asStartElement();<br />                parsingResult.append( "&lt;" );<br />                parsingResult.append( se.getName() );<br />                if( se.getName().getLocalPart().equals( "catalog" ) ) ...{<br />                    parsingResult.append( "id="" );<br />                    parsingResult.append( se.getAttributeByName( new QName( "id" ) ).getValue());<br />                    parsingResult.append( """ ) ;<br />                }<br />                parsingResult.append( ">" );<br />            } else if( event.isCharacters() ) ...{<br />                parsingResult.append( event.asCharacters().getData() );<br />            } else if( event.isEndElement() ) ...{<br />                parsingResult.append( "&lt;/" );<br />                parsingResult.append( event.asEndElement().getName() );<br />                parsingResult.append( ">" );<br />            }<br />        }<br />        System.out.println( parsingResult );<br />    }<br />    <br />    public static void writeXMLBySAX() throws XMLStreamException, FileNotFoundException ...{<br />        XMLOutputFactory factory = XMLOutputFactory.newInstance();<br />        XMLStreamWriter writer = factory.createXMLStreamWriter( new FileOutputStream( "output.xml" ) );<br />        writer.writeStartDocument();<br />        writer.writeCharacters( " " );<br />        writer.writeComment( "testing comment" );<br />        writer.writeCharacters( " " );<br />        writer.writeStartElement( "catalogs" );<br />        writer.writeNamespace( "myNS", "http://blog.csdn.net/Chinajash" );<br />        writer.writeAttribute( "owner", "sina" );<br />        writer.writeCharacters( " " );<br />        writer.writeStartElement("http://blog.csdn.net/Chinajash", "catalog");<br />        writer.writeAttribute("id","007");<br />        writer.writeCharacters("Apparel");<br />        // 写入catalog元素的结束标签<br />        writer.writeEndElement();<br />        // 写入catalogs元素的结束标签<br />        writer.writeEndElement();<br />        // 结束 XML 文档<br />        writer.writeEndDocument();         <br />        writer.close();<br /><br />    }<br />}<br /><br />test.xml:<br /><br /> <br /><br />&lt;?xml version="1.0" encoding="UTF-8"?><br />&lt;catalogs><br />    &lt;catalog id="001">Book&lt;/catalog><br />    &lt;catalog id="002">Video&lt;/catalog><br />&lt;/catalogs><br /> <br /><br />8. Web Service. 由于Web服务日趋流行，利用Web服务的功能性的API特征正从最新的Java EE版本中向Java SE 6平台迁移。换言之，针对Web服务不需另外加入额外的工具，在Java EE和Java SE平台拥有相同的API。野马将大把不同的Web服务相关的API加到标准的工具柜中：以JSR 181针对Java 平台的Web服务元数据，通过JSR 224的基于XML 的Web服务Java API（JAX-WS）；针对Java的带有附件的SOAP API（SAAJ）作为JSR 67 。与三个Web服务API相关的包新增到Java SE 6.0里：JAX－WS API 放置到javax.xml.ws包； SAAJ类在javax.xml.soap 包； Web服务的元数据类放置在javax.jws包里。 下面是一个简单的例子，　下面的代码是要作为web service发布的类。<br /><br /><br />package hello;<br />import javax.jws.WebService;<br />import javax.xml.ws.Endpoint;<br /><br />@WebService<br />public class CircleFunctions ...{<br />    public double getArea( int radius ) ...{<br />        return Math.PI * radius * radius;<br />    }<br />    public double getCircumference( int radius ) ...{<br />        return Math.PI * radius * 2;<br />    }<br />    <br />    public static void main( String[] args ) ...{<br />        Endpoint.publish( "http://localhost:8888/WebServiceExample/circlefunctions", new CircleFunctions());<br />    }<br />}<br /><br /> <br /><br />处理的方法如下：<br />javac -d ./ CircleFunctions.java<br />wsgen hello.CircleFunctions<br />java hello.CircleFunctions<br />然后在浏览器中输入如下url,你将得到一个xml页面：<br />http: //localhost:8888/WebServiceExample/circlefunctions?WSDL <br /><br />参考网页：<br />1.Desktop和SystemTray. http://dev.yesky.com/411/3019911.shtml<br />2.Console. http://dev.yesky.com/133/3032133.shtml<br />3.Compiler API. http://developer.51cto.com/art/200701/37359.htm<br />4.HttpServer API. http://www.testage.net/QA/Dev/200701/1396.htm<br />5. 对脚本语言的支持http://blog.edwardro.com/read.php?167<br />6. 插入式注解处理API. http://ourconan.com.cn/article.php?itemid-2113-type-blog.html<br />7.SAX. http://ourconan.com.cn/article.php?itemid-2111-type-blog.html<br />8.Web Service. http://www.360doc.com/showWeb/0/0/298124.aspx<br />9.JDK1.5的Annotation<br />  http://lzqdiy.bokee.com/viewdiary.14724866.html
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188670#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:11:06 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188670</link>
        <guid>http://vanadies10.javaeye.com/blog/188670</guid>
      </item>
      <item>
        <title>C# Resource的暴露问题</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188669" style="color:red;">http://vanadies10.javaeye.com/blog/188669</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          写一个C#的程序，可能会用到一些资源和配置文件，在C#中有两种方式来暴露我们的资源，一个是Embedded Resource，一个是直接放到运行的目录下(通过Copy to local) 。对于不希望发布后能够被用户修改的资源，应该使用Embedded Resource，而那些希望用户修改的配置就直接Copy to local放到编译好的目录中就好了。对于Embedded Resource，还有一个好处是用户只需要拿到Assembly就可以了。Resource是和Assembly绑定在一起的。不会搞的一大堆的文件。那么，应该如何使用Assembly中的Embedded Resource呢？引用别人的一个列子吧。也算是给自己的一个笔记<br /><br /> <br /><br />/假设/WordProcessingML是项目的名称空间<br />string str = "WordProcessingML.emptyDoc.xml";<br />//可以使用System.Reflection.Assembly.GetExecutingAssembly().GetName().Name获得默认名称空间<br />//也可以写成这样，比较灵活string str = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + ".emptyDoc.xml";<br />System.IO.Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(str);<br />string strXml = string.Empty;<br />   System.IO.StreamReader sr = new System.IO.StreamReader(stream);<br /><br />{<br /><br />    strXml = sr.ReadToEnd();<br />}<br /><br />    m_xmlDocument.LoadXml(strXml);<br /><br />重点就是拿到这个resource的 Stream<br /><br />此外就是Embedded Resource在加载时候的命名问题，首先是项目的默认的命名空间的名字，然后是Dot'.'，然后如果是项目文件夹外的资源或者是项目文件夹下的直接资源(没有子文件夹)，那么名称就是DefaultNameSpace.ResourceName，如果有子文件夹，那么就是DefaultNameSpace.ChildFolder1.ChildFolder2.ResourceName即可。
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188669#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:09:50 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188669</link>
        <guid>http://vanadies10.javaeye.com/blog/188669</guid>
      </item>
      <item>
        <title>C#中的Assembly 版本的问题</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188667" style="color:red;">http://vanadies10.javaeye.com/blog/188667</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          写了一个简单的C#的Console Application想测试一下IBatis.Net 的一些东西。使用的是Mysql数据库，开始下载了一个MySql.Data.dll，是1.0版本的，是OK的。后来下载了一个新的Mysql.Data，是5.0的，发现启动我的Console程序的时候总是还会找那个1.0的，提示什么与预绑定信息就是1.0的，我就晕掉了。百思不得其解。我说C#写程序更新一个外部的包不会如此困难吧。搞了两三天，也在CSDN上还有M$的论坛上问。都没有结果。后来自己发现原来这个版本是在IBatis.Net的providers.confg写死的。真是ft啊ft。问题解决了。还好没有花太多的时间，不过也郁闷了我两天了。现在总是遇到这样非技术性的问题。呵呵。还是C，C++好啊。
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188667#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:09:02 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188667</link>
        <guid>http://vanadies10.javaeye.com/blog/188667</guid>
      </item>
      <item>
        <title>搞定了一个使用IBatis.Net的问题</title>
        <author>vanadies10</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://vanadies10.javaeye.com">vanadies10</a>&nbsp;
          链接：<a href="http://vanadies10.javaeye.com/blog/188666" style="color:red;">http://vanadies10.javaeye.com/blog/188666</a>&nbsp;
          发表时间: 2008年05月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          今天解决了一个IBatis.Net的使用的问题，这个问题困扰了很久。在做一个管理系统，后台Server采用的是HTTP Server+DB来提供服务。 最初使用的是Perl+BerkeleyDB，演进到Servlet+Mysql，然后又演进到ASP.NET + SQL Server，从Servlet开始ORM使用的是Hibernate，到了ASP.NET后，Hibernate转变为了NHibernate。一次偶然的机会，接触到了别人的一个系统，也想把这个管理系统中的NHibernate替换为IBatis.Net，并且把请求统一放到一个Controller进行Dispatch，也可以在Controller中加入日志、权限、验证等机制。当然，对于Struts等框架都是采用类似的机制完成的。自己也是一种借鉴和学习。在测试使用IBatis.Net的时候遇到一个问题，NHibernate的时候，插入一个对象，就可以获得这个对象对应的记录的自动生成的PK。IBatis可以通过SelectKey来做，我确实也有在Java下的例子，可是在网上看到的一些资料指出的在IBatis.Net中的用法，但是不能成功。一直搞了很久。今天终于是解决了。自己给自己记录一下吧。<br /><br />&lt;statements><br />  &lt;statement  id="INSERT-ADMIN" resultClass="int"><br />      insert into admin (lastlogin, flag, controlflag, username, password, description)<br />      values (#LastLogin#, #Flag#, #ControlFlag#, #Username#, #Password#, #Description#)<br /><br />      SELECT SCOPE_IDENTITY()  AS value<br /><br />    &lt;/statement ><br /><br />这个是正确的写法，不需要用到selectKey，自己以前的错误在两个地方，一个是在statement中没有写resultClass,另外一个就是用 select @@IDENTITY as id(value)，始终不行，这个我一直没有搞明白是什么原因。只是根据自己的需要，返回的应该是这个scope中的id，所有使用select scope_identity 就可以了。
          <br/>
          <span style="color:red;">
            <a href="http://vanadies10.javaeye.com/blog/188666#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 01 May 2008 18:08:11 +0800</pubDate>
        <link>http://vanadies10.javaeye.com/blog/188666</link>
        <guid>http://vanadies10.javaeye.com/blog/188666</guid>
      </item>
  </channel>
</rss>