﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-我的玻璃盒子</title><link>http://www.cppblog.com/epubcn/</link><description /><language>zh-cn</language><lastBuildDate>Mon, 13 Apr 2026 09:39:36 GMT</lastBuildDate><pubDate>Mon, 13 Apr 2026 09:39:36 GMT</pubDate><ttl>60</ttl><item><title>【原创】Windows下编译 openh264 小记</title><link>http://www.cppblog.com/epubcn/archive/2017/03/09/214740.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Thu, 09 Mar 2017 03:51:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2017/03/09/214740.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/214740.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2017/03/09/214740.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/214740.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/214740.html</trackback:ping><description><![CDATA[<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;">1. 安装git工具(如GitHub for Windows)，clone源码：https://github.com/cisco/openh264.git</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;">2. 安装MinGW，添加 &nbsp;%YOUR MINGW INSTALL DIR%\bin\ &nbsp;到系统环境变量 &nbsp;Path &nbsp;中，手动修改\bin\mingw32-make.exe为make.exe（不改也行，以后执行起来麻烦点）</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;">3. 运行Visual Studio Command Prompt( 如 VS2013 x86 Native Tools Command Prompt）</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;">4. 在命令行窗口中，执行%YOUR MINGW INSTALL DIR%\msys\1.0\msys.bat，把MSYS命令行窗口弄出来</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;">5. MSYS中执行一下pwd看一下当前路径，把openh264代码拷贝到当前路径下某个文件夹，新建一个也行</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333px; background-color: #ffffff;">6. 进入openh264目录，执行 &nbsp;make OS=msvc &nbsp;（注意大小写），好了。</span><img src ="http://www.cppblog.com/epubcn/aggbug/214740.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2017-03-09 11:51 <a href="http://www.cppblog.com/epubcn/archive/2017/03/09/214740.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】模拟点击Outlook命令栏中的某个按钮</title><link>http://www.cppblog.com/epubcn/archive/2013/03/18/198556.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Mon, 18 Mar 2013 10:06:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2013/03/18/198556.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/198556.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2013/03/18/198556.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/198556.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/198556.html</trackback:ping><description><![CDATA[几乎2年没来这blog了，欣慰的是居然原来的数据还在。。。。<br />正好今天帮同事解决了一个有意思的小问题，就随手写一篇blog，记录这个事情。<br /><br />背景是这样的：<br />需要通过一个和Outlook没有关系的单独exe，来执行Outlook中的某个命令按钮，而不是靠手动点击去执行。有这个需求的原因是，他希望在用户按下按钮后，起一个线程去工作，但不能block住Outlook导致用户不能正常操作。当线程结束后，再自动触发Outlook Addin中的某个按钮命令做剩余的事情。给Office写过Addin的都知道，从后台线程中访问Outlook对象模型是不被支持的（参见：http://msdn.microsoft.com/en-us/library/office/dd278301(v=office.12).aspx），所以，这就给实现需求带来了困难。那么如何实现呢？<br /><br />难点：<br />Office界面上的按钮不是一个普通的窗口，无法拿到句柄去发送WM_COMMAND消息，这就给模拟执行某个按钮命令带来了困难。<br /><br />分析：<br />用Spy++看了Outlook 2003/2007/2010的界面（其中2003/2007相同，2010的Ribbon则又是另外一种情况），可以看到，在2003/2007中，工具栏的父窗口类名叫&#8220;MsoCommandBar&#8221;，2010则相对复杂，只能看到&#8220;NetUIHWND&#8221;这一层。<br />因为我们无法直接通过窗口拿到按钮，所以只能另外想办法&#8212;&#8212;看到NetUIHWND，马上联想到DirectUI，继而就非常感谢微软提供了IAccessible这个方便的东西。可能有过IAccessible使用经验的朋友看到这里，马上就豁然开朗，没错。后面写的都是用这个东东来完成的。<br /><br />解决思路：<br />先通过FindWindow一层层找到你能访问到的&#8220;最后&#8221;一个窗口。对于Outlook 2003/2007来说，路径应该是这样的：<br /><br />rctrl_renwnd32 -&gt; MsoCommandBarDock(窗口名MsoDockTop) -&gt;&nbsp;MsoCommandBar(窗口名是你的插件工具栏名称）<br /><br />而对于Outlook 2010来说则相对多一些：<br /><br />rctrl_renwnd32 -&gt;&nbsp;MsoCommandBarDock(窗口名MsoDockTop) -&gt; MsoCommandBar（窗口名Ribbon) -&gt; MsoWorkPane(窗口名Ribbon) -&gt; NUIPane -&gt; NetUIHWND<br /><br />好了，这一层窗口句柄拿到了，接下来先获取这一层窗口的IAccessible接口，示例代码：<br /><br /><div>IAccessible* accTop = NULL;</div><div>HRESULT hr = AccessibleObjectFromWindow(hwndTOP, NULL, IID_IAccessible, (LPVOID*)&amp;accTop);<br /><br />拿到其IAccessible后，还需要继续遍历其所有子元素，2003/2007再访问两层就能拿到具体的一个按钮的IAccessible接口，而2010则要访问至少6层。<br /><br />往下讲就没什么可说的了。我贴几个关键的函数吧，请自行建一个Win32进行测试。<br /><br /><div style="padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; width: 1038.800048828125px; word-break: break-all; "><span style="color: #008080; ">&nbsp;1</span>&nbsp;BOOL&nbsp;FindAccessible(IAccessible*&nbsp;accParent,&nbsp;IAccessible**&nbsp;accToFind,&nbsp;LPCTSTR&nbsp;lpctFindName)<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VARIANT*&nbsp;vt_output&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bRet&nbsp;=&nbsp;FALSE;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(accParent&nbsp;==&nbsp;NULL)<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">return</span>&nbsp;FALSE;<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">long</span>&nbsp;lChildCount&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT&nbsp;hr&nbsp;=&nbsp;accParent-&gt;get_accChildCount(&amp;lChildCount);<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(FAILED(hr)&nbsp;||&nbsp;(lChildCount&nbsp;==&nbsp;0))<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">return</span>&nbsp;FALSE;<br /><span style="color: #008080; ">12</span>&nbsp;<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vt_output&nbsp;=&nbsp;<span style="color: #0000ff; ">new</span>&nbsp;VARIANT[lChildCount];<br /><span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">for</span>(<span style="color: #0000ff; ">int</span>&nbsp;i=0;&nbsp;i&lt;lChildCount;&nbsp;i++)<br /><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VariantInit(&amp;vt_output[i]);<br /><span style="color: #008080; ">16</span>&nbsp;<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">long</span>&nbsp;lNewChildCount&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;=&nbsp;AccessibleChildren(accParent,&nbsp;0,&nbsp;lChildCount,&nbsp;vt_output,&nbsp;&amp;lNewChildCount);<br /><span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(FAILED(hr))<br /><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">goto</span>&nbsp;exit;<br /><span style="color: #008080; ">21</span>&nbsp;<br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">for</span>(<span style="color: #0000ff; ">int</span>&nbsp;j=0;&nbsp;j&lt;lNewChildCount;&nbsp;j++)<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(vt_output[j].vt&nbsp;==&nbsp;VT_DISPATCH)<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IDispatch*&nbsp;disp&nbsp;=&nbsp;vt_output[j].pdispVal;<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;=&nbsp;disp-&gt;QueryInterface(IID_IAccessible,&nbsp;(<span style="color: #0000ff; ">void</span>**)accToFind);<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(FAILED(hr))<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">continue</span>;<br /><span style="color: #008080; ">30</span>&nbsp;<br /><span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VARIANT&nbsp;vChildID;<br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VariantInit(&amp;vChildID);<br /><span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vChildID.vt&nbsp;=&nbsp;VT_I4;<br /><span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vChildID.lVal&nbsp;=&nbsp;CHILDID_SELF;<br /><span style="color: #008080; ">35</span>&nbsp;<br /><span style="color: #008080; ">36</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BSTR&nbsp;name;<br /><span style="color: #008080; ">37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr&nbsp;=&nbsp;(*accToFind)-&gt;get_accName(vChildID,&nbsp;&amp;name);<br /><span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(FAILED(hr))<br /><span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SysFreeString(name);<br /><span style="color: #008080; ">41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">continue</span>;<br /><span style="color: #008080; ">42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">43</span>&nbsp;<br /><span style="color: #008080; ">44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(name&nbsp;==&nbsp;NULL)<br /><span style="color: #008080; ">45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">continue</span>;<br /><span style="color: #008080; ">46</span>&nbsp;<br /><span style="color: #008080; ">47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ODF(_T("get_accName=%s\n"),&nbsp;name);<br /><span style="color: #008080; ">48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>((lpctFindName&nbsp;!=&nbsp;NULL)&nbsp;&amp;&amp;&nbsp;_tcsicmp(name,&nbsp;lpctFindName)&nbsp;==&nbsp;0)<br /><span style="color: #008080; ">49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">50</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">yes,&nbsp;we&nbsp;found!<br /></span><span style="color: #008080; ">51</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">accToFind&nbsp;now&nbsp;hold&nbsp;the&nbsp;IAccessible&nbsp;pointer&nbsp;we&nbsp;need</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">52</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bRet&nbsp;=&nbsp;TRUE;<br /><span style="color: #008080; ">53</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SysFreeString(name);<br /><span style="color: #008080; ">54</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">break</span>;<br /><span style="color: #008080; ">55</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">56</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">else</span><br /><span style="color: #008080; ">57</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">58</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(&nbsp;(lpctFindName&nbsp;==&nbsp;NULL)<br /><span style="color: #008080; ">59</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp;&nbsp;(_tcslen(name)&nbsp;==&nbsp;0)&nbsp;)<br /><span style="color: #008080; ">60</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">61</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">ok,&nbsp;may&nbsp;be&nbsp;find&nbsp;a&nbsp;NAMELESS&nbsp;object</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">62</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bRet&nbsp;=&nbsp;TRUE;<br /><span style="color: #008080; ">63</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SysFreeString(name);<br /><span style="color: #008080; ">64</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">break</span>;<br /><span style="color: #008080; ">65</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">66</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">67</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SysFreeString(name);<br /><span style="color: #008080; ">68</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">69</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">70</span>&nbsp;exit:<br /><span style="color: #008080; ">71</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(vt_output)<br /><span style="color: #008080; ">72</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">73</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">for</span>(<span style="color: #0000ff; ">int</span>&nbsp;k=0;&nbsp;k&nbsp;&lt;&nbsp;lChildCount;&nbsp;k++)<br /><span style="color: #008080; ">74</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VariantClear(&amp;vt_output[k]);<br /><span style="color: #008080; ">75</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;vt_output;<br /><span style="color: #008080; ">76</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">77</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">return</span>&nbsp;bRet;<br /><span style="color: #008080; ">78</span>&nbsp;}</div></div><br />上面函数，给出一个父节点的IAccessible和要匹配的子节点名称，来获取子节点的IAccessible接口。<br /><br />下面贴一个调用代码（for 2003/2007）：<br /><br /><div style="padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; width: 1038.800048828125px; word-break: break-all; "><span style="color: #008080; ">&nbsp;1</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HWND&nbsp;hwndOutlookWnd&nbsp;=&nbsp;FindWindow(_T("rctrl_renwnd32"),&nbsp;NULL);<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HWND&nbsp;hwndTopBarDock&nbsp;=&nbsp;FindChildWnd(hwndOutlookWnd,&nbsp;_T("MsoCommandBarDock"),&nbsp;_T("MsoDockTop"));<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HWND&nbsp;hwndOneClickBar&nbsp;=&nbsp;FindChildWnd(hwndTopBarDock,&nbsp;_T("MsoCommandBar"),&nbsp;_T("你的工具栏名称"));<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IAccessible*&nbsp;accTop&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT&nbsp;hr&nbsp;=&nbsp;AccessibleObjectFromWindow(hwndOneClickBar,&nbsp;NULL,&nbsp;IID_IAccessible,&nbsp;(LPVOID*)&amp;accTop);<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(FAILED(hr))<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">return</span>&nbsp;FALSE;<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IAccessible*&nbsp;accToFind&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(&nbsp;FindAccessible(accTop,&nbsp;&amp;accToFind,&nbsp;_T("工具栏名称"))&nbsp;)<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">we&nbsp;found&nbsp;the&nbsp;OneClick&nbsp;toolbar&nbsp;IAccessbile&nbsp;pointer<br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">now&nbsp;we&nbsp;need&nbsp;to&nbsp;find&nbsp;'PUSH&nbsp;BUTTON'&nbsp;IAccessible&nbsp;pointer</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IAccessible*&nbsp;accBtn&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">16</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(&nbsp;FindAccessible(accToFind,&nbsp;&amp;accBtn,&nbsp;_T("PUSH&nbsp;BUTTON"))&nbsp;&amp;&amp;&nbsp;(accBtn&nbsp;!=&nbsp;NULL)&nbsp;)<br /><span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">oh&nbsp;yes,&nbsp;we&nbsp;found&nbsp;the&nbsp;button<br /></span><span style="color: #008080; ">19</span>&nbsp;<span style="color: #008000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">now&nbsp;do&nbsp;its&nbsp;default&nbsp;action&nbsp;(push&nbsp;down)</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VARIANT&nbsp;varID;<br /><span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VariantInit(&amp;varID);<br /><span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;varID.vt&nbsp;=&nbsp;VT_I4;<br /><span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;varID.lVal&nbsp;=&nbsp;CHILDID_SELF;<br /><span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;accBtn-&gt;accDoDefaultAction(varID);<br /><span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VariantClear(&amp;varID);<br /><span style="color: #008080; ">26</span>&nbsp;<br /><span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bRet&nbsp;=&nbsp;TRUE;<br /><span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAFE_RELEASE_COM_POINTER(accBtn);<br /><span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAFE_RELEASE_COM_POINTER(accTop);<br /><span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAFE_RELEASE_COM_POINTER(accToFind);</div><br />里面用到的几个辅助方法：<br /><br /><div style="padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; width: 1038.800048828125px; word-break: break-all; "><span style="color: #008080; ">&nbsp;1</span>&nbsp;HWND&nbsp;FindChildWnd(HWND&nbsp;hParent,&nbsp;LPCTSTR&nbsp;lpctClassName,&nbsp;LPCTSTR&nbsp;lpctWndName&nbsp;=&nbsp;NULL)<br /><span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br /><span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HWND&nbsp;hChild&nbsp;=&nbsp;NULL;<br /><span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">int</span>&nbsp;nCount&nbsp;=&nbsp;0;<br /><span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">while</span>(nCount&nbsp;&lt;&nbsp;30)<br /><span style="color: #008080; ">&nbsp;6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(&nbsp;NULL&nbsp;!=&nbsp;(hChild&nbsp;=&nbsp;::FindWindowEx(hParent,&nbsp;NULL,&nbsp;lpctClassName,&nbsp;lpctWndName))&nbsp;)<br /><span style="color: #008080; ">&nbsp;8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br /><span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">break</span>;<br /><span style="color: #008080; ">10</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCount++;<br /><span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">return</span>&nbsp;hChild;<br /><span style="color: #008080; ">14</span>&nbsp;}</div><br /><div style="padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; width: 1038.800048828125px; word-break: break-all; "><span style="color: #008080; ">1</span>&nbsp;<span style="color: #0000ff; ">#define</span>&nbsp;SAFE_RELEASE_COM_POINTER(ptr)&nbsp;\<br /><span style="color: #008080; ">2</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;\<br /><span style="color: #008080; ">3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff; ">if</span>(&nbsp;(ptr)&nbsp;!=&nbsp;NULL&nbsp;)&nbsp;\<br /><span style="color: #008080; ">4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;\<br /><span style="color: #008080; ">5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ptr-&gt;Release();&nbsp;\<br /><span style="color: #008080; ">6</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ptr)&nbsp;=&nbsp;NULL;&nbsp;\<br /><span style="color: #008080; ">7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;\<br /><span style="color: #008080; ">8</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div><br /><br />最后要说的是，谢谢你， IAccessible 君。^_^<img src ="http://www.cppblog.com/epubcn/aggbug/198556.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2013-03-18 18:06 <a href="http://www.cppblog.com/epubcn/archive/2013/03/18/198556.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]VS2008工程转成VS2005工程的方法</title><link>http://www.cppblog.com/epubcn/archive/2011/05/30/147678.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Mon, 30 May 2011 03:11:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2011/05/30/147678.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/147678.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2011/05/30/147678.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/147678.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/147678.html</trackback:ping><description><![CDATA[<ol><li>用文本编辑器打开.sln文件，将<br /><font size="+0">Microsoft Visual Studio Solution File, Format Version 10.00<br /># Visual Studio 2008<br />修改为<br />Microsoft Visual Studio Solution File, Format Version 9.00<br /># Visual Studio 2005</font></li><li>对于C++工程，用文本编辑器打开<font size="+0">.vcproj文件，</font>将<br />Version="9.00"<br />修改为<br />Version="8.00"<br />然后再删除<br /><font size="+0">TargetFrameworkVersion="196613"</font></li><li>对于C#工程，用文本编辑器打开<font size="+0">.csproj文件，删除文件开头的内容：<br />&lt;?xml version="1.0" encoding="utf-8"?&gt;<br />然后找到以下XML文件节点<br />&lt;Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="<a href="http://schemas.microsoft.com/developer/msbuild/2003"><font color="#103901">http://schemas.microsoft.com/developer/msbuild/2003</font></a>"&gt;<br />删除属性 ToolsVersion="3.5"<br />找到以下XML文件节点<br />&lt;Import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" /&gt;<br />将其修改为<br />&lt;Import Project="$(MSBuildBinPath)Microsoft.CSharp.targets" /&gt;</font></li><li><font size="+0">注意：对于VS2008有而VS2005无的类和命名空间，在VS2005下没法使用。在第一次运行的时候，要删除系统默认添加的新版的命名空间和类。</font></li></ol><img src ="http://www.cppblog.com/epubcn/aggbug/147678.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2011-05-30 11:11 <a href="http://www.cppblog.com/epubcn/archive/2011/05/30/147678.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]mstsc VS vnc : 远程桌面最快的原因在于RDP协议</title><link>http://www.cppblog.com/epubcn/archive/2011/05/29/147650.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Sun, 29 May 2011 14:51:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2011/05/29/147650.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/147650.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2011/05/29/147650.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/147650.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/147650.html</trackback:ping><description><![CDATA[<div><div>[转自]<a href="http://kongjian.baidu.com/newsys007/blog/item/a2673a8649164a3b67096ed2.html">http://kongjian.baidu.com/newsys007/blog/item/a2673a8649164a3b67096ed2.html<br /></a><br />一番讨论，才明白为什么windows自带的远程桌面mstsc比Ultr***NC要快。</div><div></div><div>协议，还是协议。从控制命令上入手，传送GDI命令参数，而不是屏幕的数值。绘图都由Client端实时完成。Server几乎是idle的，仅传送命令参数。</div><div></div><div>Microsoft的远程桌面协议(Remote Desktop Protocol，简称RDP)</div><div></div><div>它仅传输服务器所显示的对象的属性变化的控制值，实现快速远程控制，相对于其它采用抓屏图片压缩的远程控制软件，如PCAnyWhere等而言，速度更快，控制更准确。</div><div></div><div>1) winxp 使用自带的mstsc,占用资源少，节约CPU。</div><div></div><div>看mov确实不卡。 时间流上看不出来。但是用souceinsight,word这些可能就是不行。一直在交互。毕竟有严迟。感觉上不爽。</div><div></div><div>2) VNC系列。</div><div></div><div>Ultr***NC,从驱动程序入手，自带Video Mirror Driver，速度极大提升。比起其他抓屏幕的垃圾算法软件，改善很多。 &nbsp;</div><div></div><div>刷新还是太卡。 屏幕没有像mstsc自适用。</div><div></div><div>3) Dameware</div><div></div><div>Dameware一直以来以速度快,支持客户端免安装(实际上是远程自动安装)而在远程控制软件领域深受广大管理员喜爱.</div><div></div><div>支持Microsoft RDP协议, 用这个远程控制winxp和win2003，效果和微软的远程桌面工具一样快。</div><div></div><div>4) 提高终端服务并发连接数: ThinSoft.WinConnect.Server.XP</div><div></div><div>windows xp的rdp有1个并发数的连接限制。</div><div></div><div>而WinConnect.Server.XP可以突破这个限制，最大可以拥有21个并发连接数。</div><div></div><div>官方网站：</div><div></div><div>http://www.thinsoftinc.com/products_winconserver_info.html</div><div></div><div>针对xp/2k3 sp1。</div><div></div><div>5)其他的，抓屏幕的垃圾设计软件：</div><div></div><div>Radmin不比VNC快。延迟比较严重。有放卡片的感觉。切换窗口时。没什么强的。不如VNC。</div><div></div><div>PCAnywhere 块头太大了，垃圾一个，性能太差。以前win98年代还有竞争力。现在不实用。</div><div></div><div>写这些软件的猪头们，&#8220;只顾埋头拉车，不会抬头看路&#8221;。</div><div></div><div>一点也没有理解控制报文和数据报文的区别！设计上就是垃圾，算法再好，也是没有效率的。</div><div></div><div>设计是软件的核心。核心是烂的，什么也别说了。再改进也没什么意义。</div><div></div><div>其他讨论：</div><div></div><div>6)</div><div></div><div>与朋友的讨论，搜到一篇帖子：</div><div></div><div>Ask Slashdot: Which VNC Software is Best?</div><div></div><div>http://ask.slashdot.org/article.pl?sid=04/10/20/0132236&amp;tid=185&amp;tid=201&amp;tid=4</div><div></div><div>这个帖子里面，每个人使用的感觉都不同("YMMV--Your mileage may vary" 真是很好用的一句话)，</div><div></div><div>有人说这个好，有人说那个好，每个人的经验/感觉都不同。下面是其中的一篇总结：</div><div></div><div>RealVNC: the original.</div><div></div><div>TightVNC: optimized for low-bandwidth</div><div></div><div>Ultra: tons of extras - file transfer, chat, video driver, NT/AD security</div><div></div><div>Tridia: get around firewalls, more management features</div><div></div><div>其他相关的东西：</div><div></div><div>1. VNC Loop</div><div></div><div>http://en.wikipedia.org/wiki/VNC_Loop</div><div></div><div>2. RealVNC Password Decrypter</div><div></div><div>http://jonas.pie.la/page/code.html#vncdec</div><div></div><div>3. FreeNX (据说速度比 VNC 快很多，号称可以达到接近本地的速度)</div><div></div><div>http://freenx.berlios.de/download.php</div><div></div><div>7)</div><div></div><div>http://topic.csdn.net/t/20040612/20/3086704.html</div><div></div><div>远程传输屏幕行为的方案!(讨论)</div><div></div><div>HunterForPig (留着口水的猪) &nbsp; &nbsp; 2004-06-12 20:50:24 在 VC/MFC / 网络编程 提问</div><div></div><div>实现方式： &nbsp;</div><div></div><div>在网络上传输这一屏幕行为 &nbsp;</div><div></div><div>每秒钟截屏12次！压缩成jpeg, &nbsp;</div><div></div><div>所以每截一次,传输图像数据一次 &nbsp;</div><div></div><div>&nbsp;&nbsp;&nbsp;</div><div></div><div>发现服务器端cpu使用率为100%, &nbsp;</div><div></div><div>晕了,不知还有何其它方法记录下屏幕行为, &nbsp;</div><div></div><div>或者降低cpu使用率! &nbsp;</div><div></div><div>&nbsp;&nbsp;&nbsp;</div><div></div><div>Video &nbsp; Mirror &nbsp; Driver &nbsp;</div><div></div><div>如果想解决CPU占用率的问题，最根本的解决方案是从驱动程序入手，Windows &nbsp; 2000以上已经支持Mirror &nbsp; Driver，</div><div></div><div>并且已经有一些远程监控的产品使用了此技术。如果搂主熟悉驱动编程，或许可以研究研究此种方法。 &nbsp;</div><div></div><div>诸位讨论很热烈，那我也来凑凑热闹。 &nbsp; &nbsp; &nbsp;</div><div></div><div>shootingstars，你的知识面看来比较广，在这个问题上考虑到了驱动程序。事实上，运用过滤驱动截图是最好的解决方案，主要包括以下两个技术点： &nbsp;</div><div></div><div>&nbsp;&nbsp;&nbsp;</div><div></div><div>1 &nbsp; 第一屏传输。第一屏的速度是衡量屏幕传输效率的重要参数，一般来说，用过滤驱动完成截图，并直接压缩到Socket的缓冲区，能够获取最快的速度，</div><div></div><div>&nbsp;&nbsp; &nbsp; &nbsp; 压缩算法中Intel &nbsp; MPEG4是一个很好的选择。</div><div></div><div>&nbsp;&nbsp;&nbsp;</div><div></div><div>2 &nbsp; 局部截屏传输。屏幕并不是一个整体，而是大量象素组合成的，我们只需要以一定的速率(祯率)来截取变化的像素，并发送到目标机器，就可以获得极高的传输速率。 &nbsp; &nbsp;&nbsp;</div><div></div><div>当然，如何对屏幕进行局部截取，以及如何判断变化的像素，都是很大的难题，需要用过滤驱动来解决。事实上，国内外的一些软件已经实现了这一功能，比如WinXP和Lanstar。</div><div></div></div><img src ="http://www.cppblog.com/epubcn/aggbug/147650.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2011-05-29 22:51 <a href="http://www.cppblog.com/epubcn/archive/2011/05/29/147650.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]TightVNC 1.3.x src的基本结构及一些概念</title><link>http://www.cppblog.com/epubcn/archive/2011/05/27/147380.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Fri, 27 May 2011 09:14:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2011/05/27/147380.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/147380.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2011/05/27/147380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/147380.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/147380.html</trackback:ping><description><![CDATA[<div><span style="font-family: verdana, sans-serif; ">&nbsp;&nbsp; &nbsp;TightVNC(Tight Virtual Network Computing)是一个远程桌面控制的开源软件,详情请参考<a href="http://www.tightvnc.com/index.html" style="text-decoration: none; color: #006bad; ">http://www.tightvnc.com</a>.下载了TightVNC的代码，分析了一下其Server部分的代码， WinVNC下的文件很多，但我们按照它们各自的功能做一下划分,其结构如下：<br /><table bgcolor="#99cc33" border="0"><tbody><tr bgcolor="#eeeeee"><td>Kernel</td><td>vncBuffer.cpp vncClient.cpp vncDesktop.cpp vncServer.cpp WinVNC.cpp</td></tr><tr bgcolor="#eeeeee"><td bgcolor="#eeeeee">GUI</td><td>vncAbout.cpp vncAcceptDialog.cpp vncAdvancedProperties.cpp vncConnDialog.cpp vncMenu.cpp vncProperties.cpp vncTimedMsgBox.cpp</td></tr><tr bgcolor="#eeeeee"><td bgcolor="#eeeeee">Misc</td><td>d3des.c Log.cpp MinMax.cpp RectList.cpp stdhdrs.cpp tableinitcmtemplate.cpp tableinittctemplate.cpp tabletranstemplate.cpp translate.cpp vncauth.c vncInstHandler.cpp vncKeymap.cpp vncRegion.cpp&lt; vncService.cpp</td></tr><tr bgcolor="#eeeeee"><td bgcolor="#eeeeee">Network</td><td>VSocket.cpp vncSockConnect.cpp vncHTTPConnect.cpp rfbproto.h</td></tr><tr bgcolor="#eeeeee"><td bgcolor="#eeeeee">Encoding</td><td>vncEncodeCoRRE.cpp vncEncodeHexT.cpp vncEncoder.cpp vncEncodeRRE.cpp vncEncodeTight.cpp vncEncodeZlib.cpp vncEncodeZlibHex.cpp</td></tr></tbody></table><br /><br /><br /><br />其服务端的主要功能模块结构如下：<br />其核心框架就是四个类vncClient，vncServer，vncDesktop和vncBuffer.下面我就这四个类之间的联系和用途来作一下简单的分析：<br />vncServer：<br />&nbsp;&nbsp;&nbsp;&nbsp;vncServer 主要是做如下的一些工作：容许vncClient动态的添加和删除；将本地vncDesktop对象内部状态的任何改变"传播"到各个客户端；传播客户端的鼠标和键盘事件到本地的vncDesktop对象。同时，其还创建了vncSockConnect，vncCORBAConnect和 vncHTTPConnect来接受Socket,Corba和HTTP的连接。 vncServer为每个连接上来的客户端分配了一个ClientID（其实就是内部客户对象数组的Index），并且提供了对客户端管理的众多函数：<pre>virtual void DisableClients(BOOL state); virtual void KillClient(vncClientId client); virtual void KillAuthClients(); virtual void KillUnauthClients();  virtual vncClient* GetClient(vncClientId clientid); vncClientId AddClient(VSocket *socket, BOOL auth, BOOL shared); virtual void RemoveClient(vncClientId client); </pre>同时，vncServer还提供了对客户Teleport，Capability，KeyboardEnabled，PointerEnabled，Name，Authenticated属性的get/set方法。<br />下面我们来看一下vncServer对客户端连接上来和客户端认证成功这两个事件的处理流程：<br />vncServer::AddClient：<br />&nbsp;&nbsp;&nbsp;&nbsp; 首先vncServer在其内部的vncClient *m_clientmap[MAX_CLIENTS]数组中为新连接上的客户端分配一个空闲的slot，并将其作为此客户的 clientID. 然后，为此连接分配一个vncClient对象，根据传递过来的参数，设置vncClient对象的相关属性，然后调用vncClient::Init方法将vncServer的实例指针和 clientID传给vncClient实例。接着，m_clientmap[clientid] = client并将此用户加入vncServer的未认证用户链表。<br />vncServer::Authenticated(vncClientId clientid)：<br />&nbsp;&nbsp;&nbsp;&nbsp; 首先从未认证用户列表中根据clientid获取vncClient对象，并将其从unauth list 中删除。如果是vncServer的第一个用户，创建vncDesktop对象，并调用m_desktop-&gt;Init(this)来初始化该 vncDesktop对象。接下来，为这个用户分配一个vncBuffer *buffer = new vncBuffer(m_desktop);并通过调用vncClient::SetBuffer为vncClient设置这个Buffer，最后将此用户添加到auth list中。<br />&nbsp;&nbsp;&nbsp;&nbsp;vncServer提供了一个用户列表的操作接口，这些接口通过将vncServer的方法调用映射到对auth list中各个客户的同样的方法的函数调用，这些方法有：<pre>virtual void TriggerUpdate(); virtual void UpdateRect(RECT &amp;rect); virtual void UpdateRegion(vncRegion &#174;ion); virtual void CopyRect(RECT &amp;dest, POINT &amp;source); virtual void UpdateMouse(); virtual void UpdateClipText(LPSTR text); virtual void UpdatePalette(); </pre>vncDesktop:<br />&nbsp;&nbsp;&nbsp;&nbsp;vncDesktop是一个全局唯一的对象，根据注释，vncDesktop主要是处理从display buffer中获取数据；同时，它还利用RFBLib DLL为vncServer提供诸如鼠标移动和屏幕更新等信息。上面提到，vncServer在第一个用户连接上来时发现其m_desktop为空时就创建一个vncDesktip对象，并调用 vncDesktop::Init(this)对其初始化.在vcnDesktop::Init的实现中我们发现其创建了一个 vncDesktopThread，vncDesktop的方法调用大部分都在这个vncDesktopThread里完成的.下面我们来分析一下这个线程都做了些什么:<br />vncDesktopThread::run_undetached(void *arg)：<br />&nbsp;&nbsp;&nbsp;&nbsp; 首先调用vncDesktop::Startup初始化，vncDesktop对象（见vncDesktop::Startup），然后就是处理桌面消息，调用 m_server-&gt;UpdateMouse()和m_server-&gt;UpdateRegion(rgncache) ，接下来调用vncServer::TriggerUpdate来发送屏幕更新到每个vncClient.然后就是处理RFB_SCREEN_UPDATE和RFB_MOUSE_UPDATE这两个注册消息。&nbsp;<br /><br />vncClient:<br />&nbsp;&nbsp;&nbsp;&nbsp;vncClient做了数据发送的工作，在vncClient::SendUpdate函数的实现中，我们可以看到vncClient调用SendRFBMsg首先发送<number rectangles="" of=""></number>&nbsp;,然后SendCursorShapeUpdate发送鼠标形状更新，SendCursorPosUpdate发送鼠标Pos更新，发送SendCopyRect，最后调用SendRectangles发送需要更新的矩形的相关数据。其实每个客户端vncClient在调用vncClient::Init初始化的时候都开了一个线程，客户端的行为基本上都是在vncClientThread::run里完成的。该线程在跟客户端交互完成了认证，Pixel格式，Encoding算法等信息的协商后，就进入一个loop循环开始接受和处理远程客户端发过来的rfbSetPixelFormat，rfbSetEncodings， rfbFramebufferUpdateRequest，rfbKeyEvent，rfbPointerEvent，rfbClientCutText 消息。&nbsp;<br /><br />vncBuffer:<br />&nbsp;&nbsp;&nbsp;&nbsp;vncBuffer主要处理发送数据的Encoding工作，其提供了远程客户的本地视图，其主要是利用内部的vncDesktop指针来获取相关的数据。&nbsp;</span></div><img src ="http://www.cppblog.com/epubcn/aggbug/147380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2011-05-27 17:14 <a href="http://www.cppblog.com/epubcn/archive/2011/05/27/147380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]RFB与RDP的区别</title><link>http://www.cppblog.com/epubcn/archive/2011/05/26/147174.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Thu, 26 May 2011 03:34:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2011/05/26/147174.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/147174.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2011/05/26/147174.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/147174.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/147174.html</trackback:ping><description><![CDATA[<div><span style="font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 22px; color: #424242; "><span style="line-height: 22px; color: #008000; "><span style="line-height: 22px; ">转自：<div style="display: inline-block; "><div><a href="http://blog.163.com/vinstars@126/blog/static/16362819120104610273654/"><span>http://blog.163.com/vinstars@126/blog/static/16362819120104610273654/</span></a></div></div><br /><br /><strong>RFB (<a style="color: #555555; line-height: 22px; text-decoration: none; "></a></strong><strong style="line-height: 22px; color: black; background-color: #ffff66; font-weight: bold; ">remote</strong><strong>&nbsp;framebufer)和RDP（</strong><strong style="line-height: 22px; color: black; background-color: #ffff66; font-weight: bold; ">Remote</strong><strong>&nbsp;Desktop Protocol)</strong></span></span><br style="line-height: 22px; " /><br style="line-height: 22px; " />RFB的典型应用有VNC，HP的RGS也是类似的设计，另外一些远程控制软件也可以归为RFB RDP的典型应用有Windows的远程桌面，同时Linux, FreeBSD, Solaris ,Mac OS X以及PalmOS都有对RDP的支持。<br style="line-height: 22px; " /><br style="line-height: 22px; " /><span style="line-height: 22px; color: #ff4500; ">二者具体的区别比较可以参考</span>:&nbsp;<a href="http://www.gnome.org/~markmc/remote-desktop.html" target="_blank" style="color: #555555; line-height: 22px; text-decoration: none; ">http://www.gnome.org/~markmc/<strong style="line-height: 22px; color: black; background-color: #ffff66; ">remote</strong>-desktop.html</a>&nbsp;<br style="line-height: 22px; " /><br style="line-height: 22px; " />两种设计在声音以及协同操作方面上有不同，但对两种设计在窗口显示上进行比较，更能说明它们的本质区别。下面举两个具体的例子：<br style="line-height: 22px; " /><br style="line-height: 22px; " />1、在一台装有高端显卡的图形工作站上运行一个使用了高版本OpenGL的实时交互窗口程序，如果采用RFB，那么即使本地客户端配置较低，用的是较低端的显卡，只要网络通畅就一般能跑得很顺畅，但如果用的是RDP，即使网络再好，这个程序也永远跑不起来。<br style="line-height: 22px; " /><br style="line-height: 22px; " />2、还是用显卡配置较低的客户机登录到远端服务器，由于登录后的系统配置要求的屏幕分辨率较高，客户机不可能使用这个分辨率进行显示，为了继续运行，使用RFB的应用显示了这个桌面，这时你会发现它只显示了桌面的一部分，或者将整个桌面按比例缩小后显示出来；而使用RDP的应用就很麻烦了，客户端将通知服务器目前的状态，希望服务器改变当前配置以适应客户端能接受的分辨率。<a style="color: #555555; line-height: 22px; text-decoration: none; "></a><br style="line-height: 22px; " /><br style="line-height: 22px; " />由以上的例子可以看出：<strong style="line-height: 22px; ">RFB是在服务器端将窗口在显存中画好之后将图像传给客户端，客户端只充当一个图像解码显示的角色； RDP则将画图的工作交给了客户端，服务器需要了解客户端显示能力的具体情况，以便作出相应调整。</strong><br style="line-height: 22px; " /><br style="line-height: 22px; " />总结起来可以认为，<strong style="line-height: 22px; ">RFB主要传图像，RDP主要传指令</strong>。就一般应用而言，RFB数据量太大，RDP对客户端要求较高，因此RFB适用于瘦客户端，RDP适用于低速网络。<br style="line-height: 22px; " /><br style="line-height: 22px; " /><strong style="line-height: 22px; ">What's RDP?</strong><br style="line-height: 22px; " /><strong style="line-height: 22px; color: black; background-color: #ffff66; ">Remote</strong>&nbsp;Desktop Protocol (RDP) is a multi-channel protocol that allows a user to connect to a computer running Microsoft Terminal Services. Clients exist for most versions of Windows (including handheld versions), and other operating systems such as Linux, FreeBSD, Solaris and Mac OS X, as well as PalmOS has a client. The server listens by default on&nbsp;<strong style="line-height: 22px; ">TCP port 3389</strong>.Microsoft refers to the official RDP client software as either&nbsp;<strong style="line-height: 22px; color: black; background-color: #ffff66; ">Remote</strong>&nbsp;Desktop Connection (RDC) or Terminal Services Client (TSC).<br style="line-height: 22px; " /><br style="line-height: 22px; " /><strong style="line-height: 22px; ">What's RFB?</strong><br style="line-height: 22px; " />RFB (&#8220;<strong style="line-height: 22px; color: black; background-color: #ffff66; ">remote</strong>&nbsp;<a style="color: #555555; line-height: 22px; text-decoration: none; "></a><strong style="line-height: 22px; color: black; background-color: #a0ffff; ">framebuffer</strong>&#8221;) is a simple protocol for&nbsp;<strong style="line-height: 22px; color: black; background-color: #ffff66; ">remote</strong>&nbsp;access to graphical user interfaces. Because it works at the&nbsp;<strong style="line-height: 22px; color: black; background-color: #a0ffff; ">framebuffer</strong>&nbsp;level it is applicable to all windowing systems and applications, including X11, Windows and Macintosh. RFB is the protocol used in Virtual Network Computing (VNC) and its derivatives.<br style="line-height: 22px; " />Although RFB started as a relatively simple protocol it has been enhanced with additional features (such as file transfers) and more sophisticated compression and security techniques as it has developed. To maintain seamless cross-compatibility between the many different VNC client and server implementations, the clients and servers negotiate a connection using the best RFB version, and the most appropriate compression and security options, that they can both support.<br style="line-height: 22px; " />VNC by default uses&nbsp;<strong style="line-height: 22px; ">TCP ports 5900 through 5906,</strong>&nbsp;each port corresponding to a separate screen (:0 to :6).<br style="line-height: 22px; " /><br style="line-height: 22px; " /><strong style="line-height: 22px; ">What's VNC?</strong><br style="line-height: 22px; " />VNC（Virtual Network Computing，虚拟网络计算）最早是一套由英国剑桥大学AT&amp;T实验室在2002年开发的轻量型的远程控制计算机软件，其采用了 GPL 授权条款，任何人都可免费取得该软件。VNC软件主要由两个部分组成：VNC server及VNC viewer。用户需先将VNC server安装在被控端的计算机上后，才能在主控端执行 VNC viewer 控制被控端。&nbsp;<br style="line-height: 22px; " />VNC server 与 VNC viewer 支持多种操作系统，如 windows，Linux，MacOS 及 Unix 系列（Unix，Solaris等），因此可将 VNC server 及 VNC viewer 分别安装在不同的操作系统中进行控制。RealVNC 的优越性还在于如果操作系统的主控端计算机没有安装 VNC viewer，也可以通过一般的网络浏览器（如 IE 等）来控制被控端（需要 Java 虚拟机的支持）。<br style="line-height: 22px; " /><br style="line-height: 22px; " />整个 VNC 一般运行的工作流程如下：&nbsp;<br style="line-height: 22px; " />（1） VNC 客户端通过浏览器或 VNC Viewer 连接至 VNC Server。&nbsp;<br style="line-height: 22px; " />（2） VNC Server 传送一对话窗口至客户端，要求输入连接密码（可能为空），以及存取的 VNC Server 显示装置。&nbsp;<br style="line-height: 22px; " />（3） 在客户端输入连接密码后，VNC Server 验证客户端是否具有存取权限。&nbsp;<br style="line-height: 22px; " />（4） 若是客户端通过 VNC Server 的验证，客户端即要求 VNC Server 显示桌面环境。&nbsp;<br style="line-height: 22px; " />（5） 被控端将画面显示控制权交由 VNC Server 负责。&nbsp;<br style="line-height: 22px; " />（6） VNC Server 将把被控端的桌面环境利用 VNC 通信协议送至客户端，并且允许客户端控制 VNC Server 的桌面环境及输入装置。<br style="line-height: 22px; " /><br style="line-height: 22px; " /><span style="line-height: 22px; color: #ff4500; ">RFB协议&nbsp;</span>:&nbsp;<a href="http://en.wikipedia.org/wiki/RFB" target="_blank" style="color: #555555; line-height: 22px; text-decoration: none; ">http://en.wikipedia.org/wiki/RFB</a><br style="line-height: 22px; " /><br style="line-height: 22px; " /><span style="line-height: 22px; color: #ff4500; ">RDP协议</span>&nbsp;:&nbsp;<a href="http://en.wikipedia.org/wiki/Remote_Desktop_Protocol" target="_blank" style="color: #555555; line-height: 22px; text-decoration: none; ">http://en.wikipedia.org/wiki/<strong style="line-height: 22px; color: black; background-color: #ffff66; ">Remote</strong>_Desktop_Protocol</a><br style="line-height: 22px; " /><br style="line-height: 22px; " /><span style="line-height: 22px; color: #ff4500; ">常见远程桌面软件对比</span>&nbsp;:&nbsp;<a href="http://en.wikipedia.org/wiki/Comparison_of_remote_desktop_software" target="_blank" style="color: #555555; line-height: 22px; text-decoration: none; ">http://en.wikipedia.org/wiki/Comparison_of_<strong style="line-height: 22px; color: black; background-color: #ffff66; ">remote</strong>_desktop_software</a></span></div><img src ="http://www.cppblog.com/epubcn/aggbug/147174.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2011-05-26 11:34 <a href="http://www.cppblog.com/epubcn/archive/2011/05/26/147174.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>首页怎么乱成这个样子？</title><link>http://www.cppblog.com/epubcn/archive/2011/02/15/140088.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Tue, 15 Feb 2011 07:17:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2011/02/15/140088.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/140088.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2011/02/15/140088.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/140088.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/140088.html</trackback:ping><description><![CDATA[真的是好久好久、好久好久没写这个blog了。首页怎么乱成这个样子了？ <br><br>刚才在blog选项中鼓捣了好久，终于发现这个style不乱了，先用这个吧。
<img src ="http://www.cppblog.com/epubcn/aggbug/140088.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2011-02-15 15:17 <a href="http://www.cppblog.com/epubcn/archive/2011/02/15/140088.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>终于在我的HP 6515B 上激活了WINDOWS 7 RTM U版</title><link>http://www.cppblog.com/epubcn/archive/2009/08/29/94765.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Sat, 29 Aug 2009 07:39:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2009/08/29/94765.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/94765.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2009/08/29/94765.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/94765.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/94765.html</trackback:ping><description><![CDATA[
vista用了有一段时间了，最近看同事装了个WIN 7，挺新鲜，决定也装一个。<br>昨天晚上从远景下载了一个cn_windows_7_ultimate_x86_dvd_x15-65907.iso，刻盘，安装，然后开始艰苦的激活尝试。<br>折腾到凌晨1点，几乎所有的激活补丁、工具都试过了，就是不成功，有些想放弃了。<br><br>今天早上起来又上网搜索了一下HP 6515B相关的帖子，突然发现有人成功激活了，最早的帖子是这篇：<br><a href="http://benyouhui.it168.com/thread-985830-3-1.html">http://benyouhui.it168.com/thread-985830-3-1.html</a><br><br>然后按照帖子里面的说明，下载安装了<span style="font-family: Helvetica; border-collapse: collapse; font-size: 14px; line-height: 22px; ">grub4dos，然后把slic.bin、grldr以及menu.lst复制到C盘下。<br></span><span style="font-family: Helvetica; border-collapse: collapse; font-size: 14px; line-height: 22px; ">用SLIC_Dump_TooKit查看BIOS的SLIC版本，原来是显示Error，装了grub4dos以后，显示2.1了。<br>最后用远景论坛上一哥们儿提供的oem激活工具进行激活，重启以后还是显示没激活，郁闷。然后又执行了一遍这个激活工具的卸载，但是好像显示什么错误，不管他，重启机器。<br>不甘心那，运行SLIC_Dump_Tookit，又显示Error了，再试一遍：安装grub4dos，这下SLIC又显示2.1了。再重启机器&#8230;&#8230;<br><br>进入WIN 7，按WIN+Pause，我靠！竟然显示Windows已激活了！！哈哈哈&#8230;&#8230;鬼使神差地让我给弄好了。<br>亢奋中&#8230;&#8230;<br><br>后来又在网上发现另外一篇帖子，也是用差不多的方式激活了，不过他是导入证书并用key激活的：<a href="http://benyouhui.it168.com/thread-988200-1-1.html">http://benyouhui.it168.com/thread-988200-1-1.html</a><br>以后有机会可以试试这种方法。<br><br>接下来开始装各种各样的软件咯&#8230;&#8230;</span><img src ="http://www.cppblog.com/epubcn/aggbug/94765.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2009-08-29 15:39 <a href="http://www.cppblog.com/epubcn/archive/2009/08/29/94765.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】搜狐白社会阳光牧场外挂 UI源代码</title><link>http://www.cppblog.com/epubcn/archive/2009/08/11/92913.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Tue, 11 Aug 2009 08:14:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2009/08/11/92913.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/92913.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2009/08/11/92913.html#Feedback</comments><slash:comments>32</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/92913.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/92913.html</trackback:ping><description><![CDATA[好多朋友需要我写的阳光牧场外挂的界面代码，今天抽空打了个包，提供给各位下载。<br><br>一些说明：<br><br>1、界面主要是基于XT的早期版本（大概是4、5年前的版本）中rip出来的代码，做了一些修改。代码中还有不少问题，我没有去修正。因为我工作中写界面是不用MFC的，这次是为了写这个外挂才把以前的老界面code翻出来。<br><br>2、源代码解压后，有个XTUILib目录，里面就是rip出来的全部XT的代码。把这个目录搞到你的工程中去以后，还有很多其他事情要做：<br>（1）resource.h中所有以XT或XTP开头的资源ID，要搞到你的工程去；<br>（2）rc文件中所有以XT或XTP开头的资源（主要是一些图标、对话框、bitmap之类的）也要搞到你的工程里去，资源文件在res目录下你可以找到。<br><br>3、XT的使用，请自行到官网或国内其他编程站点找一下，这里就不赘述了。<br><br><a href="http://sohusunfarmhelper.googlecode.com/files/sohusunfarmhelper_base_ui_codes.rar" target="_blank">点击这里下载</a>（652KB）<img src ="http://www.cppblog.com/epubcn/aggbug/92913.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2009-08-11 16:14 <a href="http://www.cppblog.com/epubcn/archive/2009/08/11/92913.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】TinyJSON使用介绍</title><link>http://www.cppblog.com/epubcn/archive/2009/08/05/92267.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Wed, 05 Aug 2009 03:56:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2009/08/05/92267.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/92267.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2009/08/05/92267.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/92267.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/92267.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引用www.json.org上的对JSON这种数据格式的介绍：JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立...&nbsp;&nbsp;<a href='http://www.cppblog.com/epubcn/archive/2009/08/05/92267.html'>阅读全文</a><img src ="http://www.cppblog.com/epubcn/aggbug/92267.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2009-08-05 11:56 <a href="http://www.cppblog.com/epubcn/archive/2009/08/05/92267.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】阳光牧场外挂的主要编写思路介绍</title><link>http://www.cppblog.com/epubcn/archive/2009/07/27/91315.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Mon, 27 Jul 2009 04:38:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2009/07/27/91315.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/91315.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2009/07/27/91315.html#Feedback</comments><slash:comments>23</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/91315.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/91315.html</trackback:ping><description><![CDATA[终于有点时间写这样一些文字，来介绍我前些时间写的搜狐阳光牧场外挂。<br>其实这样的一个外挂没有什么高深的技术，只需要使用2个辅助工具和1门你熟悉的编程语言就OK了。<br><br>废话不多说，我就开门见山直接介绍了。<br><br>你需要准备2个工具：HttpWatch（或HttpAnalyzer），以及JSONViewer(http://www.codeplex.com/JsonViewer)<br>HttpWatch（或HttpAnalyzer）是收费软件，JSONViewer是free的。另外你也可以安装Firefox的JSONView插件，也可以不用JSONViewer。<br><br>编写任何一个WEB应用外挂，第一步肯定都是登录。只有正确登录了，才能继续后面的操作。<br><br>我们先拿HttpWatch来分析一下搜狐白社会的登录过程。<br><br><span style="font-weight: bold; color: red;">第一部分：登录</span><br>1、打开http://bai.sohu.com，如果你以前已经登录了，先退出来到要求你输入email和密码的页面<br>2、按下HttpWatch的Record按钮，然后在页面上输入Email和密码，点登录。然后你会进入白社会首页。这个时候看一下HttpWatch记录的轨迹，如下：<br><img  src="http://www.cppblog.com/images/cppblog_com/epubcn/01.png" border="0"><br>上面的图中我添加了filter，把图片什么的过滤掉了。<br>3、通过上面HttpWatch记录的轨迹，我们很容易看到，登录的真实URL是：<br>http://passport.sohu.com/sso/login.jsp?userid=你的E-MAIL账号&amp;password=密码串&amp;appid=1062&amp;persistentcookie=1&amp;s=1248665199215&amp;b=2&amp;w=1440&amp;pwdtype=1<br>上面地址中，userid是你登录时输入的email地址，password是经过md5加密的字符串，s是时间（1970-1-1到现在的秒数，应该是这个账号注册的时间。在C语言中可以用time()函数来产生），w应该是计算机屏幕X方向的分辨率，persistentcookie表示保存cookie，b和pwdtype是一个常量，不知道具体含义（我们也不需要关心）。<br><br>OK，通过上面我们看到的URL，就可以完成账号登录了。<br><br><span style="font-weight: bold; color: red;">第二部分：进入阳光牧场</span><br>1、打开HttpWatch的Record，点击首页左侧的&#8220;阳光牧场&#8221;，HttpWatch会将每个页面动作都记录下来。我们可以看到，阳光牧场的真实地址是http://bai.sohu.com/app/farm/。在HttpWatch中选中http://bai.sohu.com/app/farm/这条记录，在下方的Content页签中，可以看到这个页面的source code：<br><img  src="http://www.cppblog.com/images/cppblog_com/epubcn/02.png" border="0"><br>2、你可以把这个页面的source code复制出来，到dreamweaver或其他编辑器中查看，你会发现，这个网页其实包含了几个iframe。其中有一个iframe，才是真正的、中间那个阳光牧场的大flash的地址：<span style="font-weight: bold;">&lt;iframe src="http://sh_farm.rekoo.com/embed_swf/?so_sig_uid=6位数字&amp;so_sig_session_key=UXdkRmZMaUxFQjg9&amp;so_sig_sig=049fa15390e4c9acffbecac8870e83c1" frameborder="0" width="796" height="590" scrolling="no"&gt;&lt;/iframe&gt;</span><br>在上面的地址中，so_sig_uid就是你在搜狐白社会网站的用户ID，这个ID对一般用户来说没什么用，是每个用户在数据库中的标识。但是对我们编写外挂来说，就很有用了，所以在这个地方，你需要将这个ID保存下来，以后要用到。<br><br>3、在浏览器中输入http://sh_farm.rekoo.com/embed_swf
/?so_sig_uid=6位数字&amp;so_sig_session_key=UXdkRmZMaUxFQjg9&amp;so_sig_sig=049fa15390e4c9acffbecac8870e83c1，你会发现浏览器中只留下刚才我们看到的中间的那个大flash了，其他的通通都没有了。事实证明我们找到的这个iframe是正确的。（注：执行此步骤时，别忘了打开HttpWatch的Record）<br><br>4、在HttpWatch中选中上面的地址，观察一下返回的Content：<br><img  src="http://www.cppblog.com/images/cppblog_com/epubcn/03.png" border="0"><br><br>5、在上面我选中的高亮部分中，你能看到session_name、session_value、uid等一些信息。其中对我们非常重要的一个值就是session_value。有过web开发经验的朋友都知道，登录后，在站点中是有一个session在client端维护着用户的一些信息，并且这个session是每次登录都会产生的随机字符串，并且有一定的有效期（由管理权配置）。所以，我们要模拟web的动作，就需要拿到正确的session字符串，也就是上面我们看到的那个session_value。<br><br>其实到目前为止，我们的分析工作已经进行了一大半了。简单总结一下：<br>我们上面做了那么多事情，最重要达到两个目的：<br>（1）如何模拟用户登录<br>（2）获得正确的UID和sessionid<br><br>另外，关于sessionid的获取还有其他方法，例如，如果你使用的是Java，可以从cookie中读取到sessionid。<br><br><span style="font-weight: bold; color: red;">第三部分、分析阳光牧场各种操作</span><br>有了上面的基础，下面的分析简直是易如反掌了。<br>1、打开HttpWatch的Record，将上面的http://sh_farm.rekoo.com/embed_swf
/?so_sig_uid=6位数字&amp;so_sig_session_key=UXdkRmZMaUxFQjg9&amp;so_sig_sig=049fa15390e4c9acffbecac8870e83c1
重新刷新一下。<br>2、在HttpWatch中，你会看到很多这样的地址：http://sh_farm.rekoo.com/get_api/，这个地址那可是相当的重要啊，几乎所有的命令请求都是往这个地方发。<br>3、选中http://sh_farm.rekoo.com/get_api/
，在下面的POST Data中可以看到：<br><img  src="http://www.cppblog.com/images/cppblog_com/epubcn/04.png" border="0"><br>原来这是一个标准的http post请求，完整的URL就是：<span style="font-weight: bold;">http://sh_farm.rekoo.com/get_api/?method=user.get_friends&amp;rekoo_killer=你的6位UID&amp;sessionid=刚才我们从页面上获取到的session_value<br></span>然后我们点击旁边的Content页签，看到服务器返回的内容如下：<span style="font-weight: bold;"><br><img  src="http://www.cppblog.com/images/cppblog_com/epubcn/05.png" border="0"><br><br></span>上面是典型的JSON数据，接下来怎么做不用我说了吧。你可以把上面的内容复制到JSONViewer中，它提供了树形结构供你方便的展开每个节点，以分析父子关系、每个节点的类型等信息:<span style="font-weight: bold;"><br><img  src="http://www.cppblog.com/images/cppblog_com/epubcn/06.png" border="0"><br></span>4、上面我们看到的是获取好友列表的请求，其他的诸如获取商店信息、杀虫浇水、播种、收割&#8230;&#8230;请求地址都是http://sh_farm.rekoo.com/get_api/，只不过post的参数不同而已。将正确的参数post给服务器，服务器就会返回相应操作的JSON数据给你，有了这些数据，你就可以进行后期的分析处理了。<br><br>OK，通过上面文字的介绍，相信各位已经明白了，这样的一个外挂是怎么工作的了。<span style="font-weight: bold;"><br><br></span><br><img src ="http://www.cppblog.com/epubcn/aggbug/91315.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2009-07-27 12:38 <a href="http://www.cppblog.com/epubcn/archive/2009/07/27/91315.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】 搜狐白社会阳光牧场外挂（暂时不能工作聊~~%&gt;_&lt;%）</title><link>http://www.cppblog.com/epubcn/archive/2009/07/19/90564.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Sun, 19 Jul 2009 15:51:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2009/07/19/90564.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/90564.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2009/07/19/90564.html#Feedback</comments><slash:comments>454</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/90564.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/90564.html</trackback:ping><description><![CDATA[<span style="COLOR: #999999">2个月前受搜狐的一个同学推荐，加入了搜狐白社会这个SNS。感觉搜狐干什么都比别人慢一步，SNS都烂大街了，它才搞一个出来。<br>里面也有一个种菜的组件，叫阳光牧场。开始以为是搜狐自己开发的，因为外观和开心网不太一样，感觉没有走寻常路。觉得挺新鲜，就开始玩儿了。大概玩儿了1个月，觉得每天上来收割、杀虫、浇水太麻烦了，所以萌发了写一个&#8216;收割机&#8217;的想法。不过以前没写过类似东西。刚开始还觉得挺新鲜的，等这个&#8216;收割机&#8217;写的差不多了，剩下的就是工作量了。因为每天要工作，回家还要跟儿子玩儿，每天都是挤半小时一小时写一点，终于搞了一个差不多能用的beta版了。觉得这个东东对别人可能有用，所以发上来。其实还有一些想法没有开发，但为了赶在今天（今天是我儿子满8个月）发布一个版，就先把想法放一放，待以后慢慢添加吧。<br><br>这个外挂是用MFC写的，MFC写界面还是比较快，比WTL快一点，虽然体积大。网络部分也是用的MFC的封装类。比较麻烦的是JSON数据的解析，因为JSON这种数据格式在其他语言（如JAVA、C#）都有非常成熟的操作类库（比如C#有Newtonsoft.Json），C++解析起来比较麻烦，在JSON网站上提供的几个C++版本，试用了一下，觉得TinyJSON体积较小，使用起来还算方便，最后就选了它。<br><br>OK，不多说了，这是第一个beta。如果可能，我会不定期更新，添加一些新的内容的。<br>如果有用过的朋友发现了什么错误，记得告诉我。毕竟这个东东没有经过严格的测试，很多容错处理我都没有做。慢慢完善吧。<br><br></span>======================================<br><span style="COLOR: #999999">点击这里下载（v1.0 b0719）（301KB）<br>点击这里下载（v1.0 b0722）（536KB）<br>点击这里下载（v1.0 b0723）（535KB）<br>点击这里下载（v1.0 b0730）（542KB）<br>点击这里下载（v1.0 b0807）（545KB）<br>点击这里下载（v1.0 b0904）（676KB）<br>点击这里下载v1.0 b0904 Patch（660KB）<br>点击这里下载</font>（v1.0 b0909）（676KB）<br>点击这里下载（v1.0 b0925）（679KB）<br>点击这里下载（v1.0 b0930）（730KB）<br>点击这里下载（v1.0 b1110）（730KB）</span><br>==========以上版本不再提供下载==========<br><br><span style="BACKGROUND-COLOR: #ffff00">2009年12月23日<br>郁闷啊郁闷，昨天早上刚修改了程序，下午阳光牧场又改了。不知道是不是故意行为。<br>刚才重新分析了一下，发现大问题：发送的请求过去，服务器不返回数据。看来搜狐真的是在防备外挂咯。。。<br>这个问题比较麻烦，目前我还不知道怎么修改，所以新版本什么时候能发布，我也说不好了。。。<br><br>2009年12月25日<br>真是祸不单行，昨天公司竟然把白社会给封了，不能访问了，可能游戏太多了。本来想尝试一些新的方法再试试，这下歇菜了，只能回家弄了，哎没有办法利用白天的时间了，郁闷。郁闷。<br><br>另外有个朋友给我留言，说有个外挂还能用，要不大家先用这个吧：<a href="http://code.google.com/p/sunfarm/downloads/list">http://code.google.com/p/sunfarm/downloads/list</a><br>用java写的，好像没有界面，需要安装JDK，自己配置账号等信息。<br><br>啥时候能写出来新的，我也说不好了，实在抱歉。<br></span><br><a href="http://sohusunfarmhelper.googlecode.com/files/SohuSunFarmHelper_v1.0b1222.rar"><u><span style="FONT-SIZE: 18pt">点击这里下载</span></u></a><span style="FONT-SIZE: 14pt">（v1.0 b1222）（731KB）<span style="COLOR: red">（&lt;-这个现在不能用了哦，别下载了。）</span><br></span><br><span style="COLOR: #ff0000">【更新历史】<br><span style="COLOR: #000000"><span style="COLOR: #000000"><span style="COLOR: #000000"><span style="COLOR: #000000"><span style="COLOR: #000000"><span style="COLOR: #000000"><span style="COLOR: #000000"><span style="COLOR: #000000"><strong>2009.12.22<br></strong>&nbsp;1、modified：添加了几种新商品的数据（需要酷币购买）：圣诞树、松树、大白菜，麋鹿、火鸡。<br>&nbsp;2、modified：针对白社会阳光牧场代码修改导致程序不能执行偷取操作的问题修正。<br></span></span></span></span><strong><br>2009.11.10<br></strong>&nbsp;1、modified：根据近期商店数据更新，对商店明细表、工作数据做出了相应的更新<br>&nbsp;2、modified：针对2009-11-09白社会阳光牧场升级导致程序不工作的问题做了一些修改<br>&nbsp;3、modified：更改工作周期范围，调整到15分钟~120分钟，不合法的范围将被强制恢复至默认的60分钟<br></span><br></span><strong>2009.11.04 商店数据更新<br></strong>添加了新作物数据：樱桃、橘子、桂圆、红枣<br>更新了所有作物的最新数据，请在程序中主菜单&#8216;工具&#8217;中选择&#8216;查看商店明细&#8217;命令查看。<br></span></span></span><br><span style="COLOR: #000000"><span style="COLOR: #000000"><strong>2009.9.30<br></strong>1、added：添加几种需要酷币购买的商品数据（中国心、蘑菇、红辣椒、喜鹊、绿孔雀）<br>2、added：添加施肥功能（仅普通化肥）<br>3、bugfix：修复了收获哺乳动物最后一次农产品后，不能立即清理并放养新动物的问题<br>4、improved：一些界面修改<br></span><br><strong>2009.9.25</strong><br>1、added：添加商店新数据，包括几种新作物和新动物。并且修改了其他旧商品的数据。<br>2、improved：添加偷取、收获结果判断的机制，并在失败时输出错误原因。<br>3、bugfix：修复了不能收获和偷取畜牧场哺乳动物的农产品问题。<br>4、improved：修改了输出日志中的一些措辞。<br></span><br><span style="COLOR: #000000"><strong>2009.9.19 商店数据更新</strong><br>更新了新作物数据：木菠萝、柿子、捕蚊草、水蜜桃、香蕉<br>更新了新动物数据：绵羊、山羊、半细毛羊、普通奶牛<br><br><strong>2009.9.15 商店数据更新<br></strong>更新了新作物数据：柠檬、荔枝、墨西哥仙人柱<br>更新了新动物数据：广西小麻鸭、莆田黑鸭</span><br><br><strong><span style="FONT-WEIGHT: normal"><strong>v1.0 b0909<br></strong>1、修复了0904 Patch中多账号在获取花园地址时发生的问题。<br>2、bugfix：巡视周期时长设置在某种情况下不准确的问题。<br></span><br>v1.0 b0904 Patch<br></strong>修复了因9月8日白社会修改了阳光牧场的网页代码，导致0904版无法正常工作的问题。<br><br><strong>v1.0 b0904<br></strong>1、add：按成熟/下蛋时间偷取好友花园和畜牧场产品，按时收获自家花园和畜牧场产品。<br>
<div style="PADDING-LEFT: 10px">
<div style="PADDING-BOTTOM: 10px; BACKGROUND-COLOR: rgb(241,241,241); PADDING-LEFT: 10px; WIDTH: 97%; PADDING-RIGHT: 10px; BORDER-LEFT-COLOR: rgb(227,227,227); PADDING-TOP: 10px"><strong>关于按时偷取的说明</strong><br>(1) 因多方面因素影响，本程序不能保证100%偷取率。其中花园的偷取率要略高于畜牧场。<br>(2) 偷取失败时，可能发生的原因主要有以下几种，这里做一些说明：<br><strong>【所剩无几了，不能再偷了】或【没有蛋可以偷】</strong><br>可能由于程序判断增产量存在偏差，也有可能有其他好友（或外挂程序）在同时偷取，导致被瞬间偷光。因同一时刻多方偷取，是否成功存在一定的偶然性，故出现这样的提示，属于正常现象。（偷取失败多数情况都是这样的原因。）<br><strong>【还没有成熟，等成熟了再来吧】</strong><br>程序计算的作物成熟时间存在较大偏差，虽经过多次重试偷取操作，但有可能还会发生此类问题。这种情况需要继续测试和逐步改善。</div>
</div>
2、modified：巡视工作周期默认值改为60分钟，自定义设置允许范围改为30~720分钟。<br>3、add：添加给好友花园放虫功能，以及惊吓好友的动物的功能。默认不选择，可在每个账号中单独设定。<br>4、add : 添加启动画面，以提升用户体验（在账号数据量较大时，由于程序初始化加载时间过长，程序会&#8216;停滞&#8217;一定时间）<br><br><span style="COLOR: red"><font color=#000000><strong>v1.0 b0807<br></strong>1、add：添加优先播种包裹中的作物种子和动物宝宝的功能，默认不生效，可在每个账号设置页面单独设定。<br>2、add：添加检查程序新版本的功能（主菜单&#8220;帮助&#8221;-&gt;&#8220;检查更新&#8221;命令）<br>3、add：添加为好友的畜牧场的水槽添水的功能，默认不生效，可在每个账号设置页面单独设定。<br></font></span><br><strong>v1.0 b0730</strong><br>1、add：添加统计信息功能（可统计本次程序运行后发生的偷取次数、杀虫浇水、治病次数统计）<br>2、add：从旧版本程序恢复账号和程序配置信息的功能（主菜单&#8220;设置&#8221;下）<br>3、add：当向服务器发送数据请求失败时，重试的次数和间隔时间设定（&#8220;选项&#8221;对话框中）<br>4、add：每次巡视前是否先更新好友列表变为可选项（在每个账号页面中单独设定）<br>5、improved：修改播种作物以及放养动物组合框在选取改变后的处理方式，避免选择后因鼠标滚轮导致误操作。<br>6、improved：作物种子列表中，去除了不可购买的商品。作物种类添加了蒲公英。<br><br><strong>v1.0 b0723</strong><br>1、bugfix：服务器返回数据错误时，会引起程序抛出异常。<br>2、bugfix：日志中显示偷取到果实（或农产品），但实际上未偷取成功。<br>3、add：自动出售<span style="COLOR: red"></span>包裹中的果实和农产品，默认不出售，可在每个账号页面中设定。<br>4、add：自动领取每日登录奖励包<br>5、add：为畜牧场水槽添水的功能，默认不添水，可在每个账号页面中设定。<br>6、improved：减少每个操作间隔，提高任务执行速度。<br>7、improved：当服务器返回错误内容或返回空数据时，添加重试机制（5秒重试一次，共重试6次）。添加重试机制后，会改善在好友数过多时，由于服务器返回错误信息而导致进入好友牧场失败的情况。但仍不能避免在重试多次后，服务器仍然返回错误信息的情况发生。如发生这样的情况，请手动偷取。<br><br><strong>v1.0 b0722</strong><br>1、bugfix：鼠标点选账号列表会导致账号不工作<br>2、add：增加巡视任务日志的保存功能，可以在{选项}中进行设置，默认不保存日志<br>3、add：账号列表添加上移、下移按钮，以帮助用户改变账号的巡视顺序<br>4、add：添加了程序异常日志输出，如在执行巡视任务时，发生了错误，程序会将当时的情况输出到程序运行目录下的trace.txt<br>5、add：主菜单添加了&#8220;工具&#8221;-&#8220;查看商店明细&#8221;命令，执行后会打开一个excel文件，里面包含花园和畜牧场各种作物（动物）的价格、生长时间以及收益比。<br>6、improved：程序改用&#8220;在静态库中使用 MFC&#8221;编译，去除对MFC 8的几个DLL的依赖，但程序体积增长了500多KB。<br><br><strong>v1.0 b0719</strong><br>第一个版本。实现了以下基本功能：<br>1、多账号维护<br>2、当前账号的好友信息、花园牧场信息手动读取<br>3、多账号定时巡视，并按照设定对花园执行：杀虫浇水、收获、铲除、播种，对畜牧场执行：治病、收获农产品、清理动物、放养动物<br>4、可按照设定对全部好友或某些好友执行偷果实、偷农产品、帮助杀虫浇水、帮助治疗动物<br><br><span style="COLOR: red">【程序目录结构及版本升级方法】<br></span>程序目录结构如下：<br>Data（数据目录）<br>&nbsp;&nbsp;|--Store（商店数据）<br>&nbsp;&nbsp; &nbsp; &nbsp;|--Animals.ini（畜牧场动物种类信息配置文件）<br>&nbsp;&nbsp; &nbsp; &nbsp;|--Seeds.ini（花园作物种类信息配置文件）<br>&nbsp;&nbsp; &nbsp; &nbsp;|--StoreInfo.xls（商店所有商品的明细，包括收益比）<br>&nbsp;&nbsp;|--Account（添加账号后自动生成）<br>&nbsp;&nbsp;|--Config.ini（修改程序配置后自动生成）<br>Help（欢迎页）<br>SohuSunFarmHelper.exe（主程序）<br><br><strong style="COLOR: #0000ff">从v1.0 b0730版本开始，每次升级，请使用主菜单&#8220;设置&#8221;-&#8220;恢复账号及配置&#8221;命令，来恢复您的账号和程序配置信息。<br>从v1.0 b0807版本开始，您可以使用主菜单&#8220;帮助&#8221;-&#8220;检查更新&#8221;命令来检查是否有新版本发布。</strong><br><br><span style="COLOR: red">【已知问题】</span><br>1、当金币不足时，显示购买、播种成功，事实上不成功。（因此请确保自己的腰包有足够的money<img border=0 align=absMiddle src="http://www.cppblog.com/CuteSoft_Client/CuteEditor/images/emsmilep.gif">）<br>2、放虫、惊吓达到每日上限后的处理逻辑需要完善<br><br><br><img border=0 align=absMiddle src="http://www.cppblog.com/images/cppblog_com/epubcn/snap.png"> 
<img src ="http://www.cppblog.com/epubcn/aggbug/90564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2009-07-19 23:51 <a href="http://www.cppblog.com/epubcn/archive/2009/07/19/90564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]Vista下服务与桌面互交</title><link>http://www.cppblog.com/epubcn/archive/2009/01/06/71356.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Tue, 06 Jan 2009 08:59:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2009/01/06/71356.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/71356.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2009/01/06/71356.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/71356.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/71356.html</trackback:ping><description><![CDATA[原文链接：http://www.cnblogs.com/lifeengines/archive/2008/08/26/1277054.html<br><br>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 本来在Vista之前服务与桌面互交是一件很容易的事情,自从Vista把服务都挪到Session 0
中运行去而且不可以跨Session之后,问题就复杂了许多,有时候我就在想这些问题是否真的不得不解决而且似乎对于安全并未带来多大提升的更改总是让人
头疼,Google了一些文档,抄袭了不少代码我是如下实现的</p>
<p>&nbsp;这个函数抄自winehq网站,顺便不得不说一下winehq的代码是很值得参考的</p>
<div class="cnblogs_code"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">BOOL&nbsp;WINAPI&nbsp;EnablePrivilege(LPSTR&nbsp;lpPrivilegeName,&nbsp;BOOL&nbsp;bEnable)<br>
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">{<br>
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;TOKEN_PRIVILEGES&nbsp;Privileges;<br>
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hToken;<br>
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bResult;<br>
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">OpenProcessToken(GetCurrentProcess(),&nbsp;TOKEN_QUERY,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">hToken))<br>
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;FALSE;<br>
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;"><br>
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;Privileges.PrivilegeCount&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">1</span><span style="color: #000000;">;<br>
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;Privileges.Privileges[</span><span style="color: #800080;">0</span><span style="color: #000000;">].Attributes&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(bEnable)&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;SE_PRIVILEGE_ENABLED&nbsp;:&nbsp;</span><span style="color: #800080;">0</span><span style="color: #000000;">;<br>
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;"><br>
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">LookupPrivilegeValue(NULL,&nbsp;lpPrivilegeName,<br>
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">Privileges.Privileges[</span><span style="color: #800080;">0</span><span style="color: #000000;">].Luid))<br>
</span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{<br>
</span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hToken);<br>
</span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;FALSE;<br>
</span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br>
</span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;"><br>
</span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;bResult&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;AdjustTokenPrivileges(hToken,&nbsp;FALSE,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">Privileges,&nbsp;</span><span style="color: #800080;">0</span><span style="color: #000000;">,&nbsp;NULL,&nbsp;NULL);<br>
</span><span style="color: #008080;">20</span>&nbsp;<span style="color: #000000;"><br>
</span><span style="color: #008080;">21</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hToken);<br>
</span><span style="color: #008080;">22</span>&nbsp;<span style="color: #000000;"><br>
</span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;bResult;<br>
</span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;">}</span></div>
<p>&nbsp;</p>
<p>EnablePrivilege用来提升本进程权限,因为我们的核心思路是用CreateProcessAsUser创建进程到需要互交的Session,</p>
<p>&nbsp;</p>
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">保证拥有权限</span><span style="color: #008000;"><br>
</span><span style="color: #000000;">EnablePrivilege(SE_TCB_NAME,&nbsp;TRUE);&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;EnablePrivilege(SE_CHANGE_NOTIFY_NAME,&nbsp;TRUE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;EnablePrivilege(SE_INCREASE_QUOTA_NAME,&nbsp;TRUE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME,&nbsp;TRUE);<br>
<br>
</span><span style="color: #008000;">//</span><span style="color: #008000;">获取当前进程的灵牌</span><span style="color: #008000;"><br>
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hTokenThis&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hTokenDup&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThisProcess&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;GetCurrentProcess();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OpenProcessToken(hThisProcess,&nbsp;TOKEN_ALL_ACCESS,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">hTokenThis);<br>
</span><span style="color: #008000;">//</span><span style="color: #008000;">复制令牌</span><span style="color: #008000;"><br>
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DuplicateTokenEx(hTokenThis,&nbsp;MAXIMUM_ALLOWED,NULL,&nbsp;SecurityIdentification,&nbsp;TokenPrimary,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">hTokenDup);<br>
</span><span style="color: #008000;">//</span><span style="color: #008000;">枚举所有Session,本来还有一个WTSGetActiveConsoleSessionId,不过这个函数在win2000下只有Server版本安装WTS才可以</span><span style="color: #008000;"><br>
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PWTS_SESSION_INFO&nbsp;pSInfo;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;pCInfo&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">0</span><span style="color: #000000;">;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,</span><span style="color: #800080;">0</span><span style="color: #000000;">,</span><span style="color: #800080;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pSInfo,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pCInfo);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwSessionId&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">0</span><span style="color: #000000;">;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #800080;">0</span><span style="color: #000000;">;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">pCInfo;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(pSInfo[i].State&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;WTSActive)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwSessionId&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pSInfo[i].SessionId;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">DWORD&nbsp;dwSessionId&nbsp;=&nbsp;WTSGetActiveConsoleSessionId();<br>
</span><span style="color: #008000;">//</span><span style="color: #008000;">替换令牌,关键地方,我们并不需要以Session用户创建进程,只需要替换令牌就可以了</span><span style="color: #008000;"><br>
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetTokenInformation(hTokenDup,&nbsp;TokenSessionId,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">dwSessionId,&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(DWORD));<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;STARTUPINFO&nbsp;si&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{</span><span style="color: #800080;">0</span><span style="color: #000000;">};<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PROCESS_INFORMATION&nbsp;pi&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{</span><span style="color: #800080;">0</span><span style="color: #000000;">};<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;si.cb&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(si);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;si.lpDesktop&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">WinSta0\\Default</span><span style="color: #800000;">"</span><span style="color: #000000;">;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwCreationFlag&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;NORMAL_PRIORITY_CLASS&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;CREATE_NEW_CONSOLE&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;CREATE_UNICODE_ENVIRONMENT;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;pPath[MAX_PATH</span><span style="color: #000000;">*</span><span style="color: #800080;">2</span><span style="color: #000000;">];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetModuleFileName(NULL,pPath,</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(pPath));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcat(pPath,</span><span style="color: #800000;">"</span><span style="color: #800000;">&nbsp;-work</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPVOID&nbsp;pEnv;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CreateEnvironmentBlock(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pEnv,hTokenDup,FALSE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">CreateProcessAsUser(hTokenDup,NULL,pPath,NULL,NULL,FALSE,dwCreationFlag,pEnv,NULL,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">si,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">pi))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<br>
</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;p&nbsp;=&nbsp;GetLastError();<br>
</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;=&nbsp;0;</span><span style="color: #008000;"><br>
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WaitForSingleObject(pi.hProcess,INFINITE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hTokenDup);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hTokenThis);<br>
</span><br>
这样我们的程序就可以和桌面互交了,这只是核心,其余牵涉多用户切换这些还需要另外考虑<br><br><img src ="http://www.cppblog.com/epubcn/aggbug/71356.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2009-01-06 16:59 <a href="http://www.cppblog.com/epubcn/archive/2009/01/06/71356.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】我的Firefox插件开发之旅（8）&amp;mdash;&amp;mdash;插件的安装与更新</title><link>http://www.cppblog.com/epubcn/archive/2008/11/14/66912.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Fri, 14 Nov 2008 05:57:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2008/11/14/66912.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/66912.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2008/11/14/66912.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/66912.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/66912.html</trackback:ping><description><![CDATA[
<span style="font-weight: bold;">（原创作品，转载请注明出处。）</span><br><br>
<p>插件写好了，下面就该做一个安装包了。最好再提供更新功能，以便在插件有更新的时候，及时通知用户进行插件更新。</p>
<p>我们开发的时候，直接将生成的dll丢到Firefox安装目录下的plugins目录就可以工作了，但是你如何说服让用户来手动完成这件事情？估计很难。因此，提供一个安装包，可能是最好的选择。用户只需要点几下鼠标就可以完成插件的安装了。</p>
<p>不过到写这篇文章的时候，我还不清楚怎么让安装包经过Mozilla的验证，因为没有经过验证的插件，在安装的时候会出现&#8220;仅安装信任作者的附加组件&#8221;提示对话框，提示用户仅安装受信任作者的插件。如果有人知道怎么去掉这个警告对话框，还望不吝赐教。</p>
<p>最最简单的插件安装包在这篇文章中开头处写的很清楚了：<a title="https://developer.mozilla.org/en/Shipping_a_plugin_as_an_extension" href="https://developer.mozilla.org/en/Shipping_a_plugin_as_an_extension">https://developer.mozilla.org/en/Shipping_a_plugin_as_an_extension</a></p>
<p>安装包的目录结构：</p>
<p>install.rdf<br>plugins/<br>&nbsp;&nbsp;&nbsp; pluginlib.dll<br>&nbsp;&nbsp;&nbsp; plugintypes.xpt  </p>
<p>其中xpt文件可选。install.rdf的内容为：  </p>
<p>&lt;RDF xmlns="<a href="http://www.w3.org/1999/02/22-rdf-syntax-ns#%22">http://www.w3.org/1999/02/22-rdf-syntax-ns#"</a> xmlns:em="<a href="http://www.mozilla.org/2004/em-rdf#%22">http://www.mozilla.org/2004/em-rdf#"</a>&gt;<br>&nbsp; &lt;Description about="urn:mozilla:install-manifest"&gt;<br>&nbsp;&nbsp;&nbsp; &lt;em:id&gt;mypluginid@myplugin.com&lt;/em:id&gt;<br>&nbsp;&nbsp;&nbsp; &lt;em:name&gt;My Plugin&lt;/em:name&gt;<br>&nbsp;&nbsp;&nbsp; &lt;em:version&gt;1.0&lt;/em:version&gt;<br>&nbsp;&nbsp;&nbsp; &lt;em:targetApplication&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Description&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:id&gt;{ec8030f7-c20a-464f-9b0e-13a3a9e97384}&lt;/em:id&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:minVersion&gt;1.5&lt;/em:minVersion&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:maxVersion&gt;3.0.*&lt;/em:maxVersion&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Description&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/em:targetApplication&gt;<br>&nbsp; &lt;/Description&gt;<br>&lt;/RDF&gt;  </p>
<p>将上面内容安装目录结构用zip格式压缩，将后缀名改为xpi就OK了。</p>
<p>但是我们要做得事情远不止这些：</p>
<ul>
    <li>如何提供插件的更新自动通知？  </li>
    <li>如何将扩展和插件捆绑在一起让用户安装？（因为可能你不仅仅要安装插件，还希望在用户的FF工具栏或菜单上添加一些扩展功能）  </li>
    <li>如何对插件进行签名？  </li>
    <li>如何发布你的插件和扩展，以便让更多人知晓？</li>
</ul>
<p>要做的事情还很多。那么我们就一个个来研究吧。</p>
<p><strong>一、如何提供插件的更新自动通知？</strong></p>
<p>关于Install manifest（即install.rdf）文件内容，Mozilla有篇很详细的文章：<a title="https://developer.mozilla.org/en/Install.rdf" href="https://developer.mozilla.org/en/Install.rdf">https://developer.mozilla.org/en/Install.rdf</a>，可以进行参考。</p>
<p>其中有个节点名称是：updateURL。用这个标签包含一个可查询更新信息的URL连接，今后当FF在查询插件是否有更新时，会到你指定的这个URL上去查询。</p>
<p>这个URL可以是一个cgi程序、servlet、asp(x)，也可以是一个固定的rdf文件链接。另外文章中也提到了另外一种办法：如果你没有提供updateURL，FF的附加组件管理器会向addons.mozilla.org发送请求，当你上传了一个新版本的插件或者通过作者接口（author interface）更改了兼容性参数，一个更新的manifest文件将会被自动产生。另外，Mozilla建议updateURL使用https而非http，否则你应该提供updateKey（可以用<a href="https://developer.mozilla.org/en/McCoy" target="_blank">McCoy</a>生成）。</p>
<p>那么，负责更新的rdf怎么编写呢？你可以参考这篇文章：<a title="https://developer.mozilla.org/en/Extension_Versioning%2c_Update_and_Compatibility#Update_RDF_Format" href="https://developer.mozilla.org/en/Extension_Versioning%2c_Update_and_Compatibility#Update_RDF_Format">https://developer.mozilla.org/en/Extension_Versioning%2c_Update_and_Compatibility#Update_RDF_Format</a>。由于文章中写的很清晰，并且提供了详细的例子代码，这里我就不废话了。</p>
<p><strong>二、如何将扩展和插件捆绑在一起让用户安装？</strong></p>
<p>这个很简单。之前的章节我们已经做过一个简单的Extension安装包，如果想附加一个插件的话，只需要和chrome的同级目录下新建一个plugins目录，然后将dll及相关文件放在里面，最后一起打包即可。</p>
<p>当在FF中安装此xpi时，FF会将Extension和Plugin解压到FF的Profiles目录下。插件和扩展即可生效。</p>
<p>注意这里与我们之前将插件dll放在FF安装目录下的plugins目录下有些不同（至少位置不同），FF同样能够正确地识别我们的插件。另外Mozilla也推荐做成安装包，这样，在用户卸载组件的时候，可以同时将Extension和Plugin都卸载掉。</p>
<p><strong>三、如何对插件进行签名？</strong>&nbsp; </p>
<p>很抱歉，还没找到答案&#8230;&#8230; </p>
<p><strong>四、 如何发布你的插件和扩展，以便让更多人知晓？</strong></p>
<p>首先需要在Mozilla网站上注册一个账号（需要提供合法E-mail，因为要激活）。</p>
<p>登录后，在Mozilla 附加组件首页上你会看到一个&#8220;开发者工具&#8221;的链接。进入后，会有明显的导航链接，如&#8220;提交附加组件&#8221;。通过这个页面，按照向导，你就可以将你的插件发布出来了。剩下的事，就是宣传咯，呵呵。</p>
<p>OK，《我的Firefox插件开发之旅》系列文章就先到这里。将来我也许还会写一些关于编写FF的Extension和Plugin方面的技术细节文章。看心情吧，呵呵。</p><img src ="http://www.cppblog.com/epubcn/aggbug/66912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2008-11-14 13:57 <a href="http://www.cppblog.com/epubcn/archive/2008/11/14/66912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】我的Firefox插件开发之旅（7）&amp;mdash;&amp;mdash;为插件添加和脚本交互的能力</title><link>http://www.cppblog.com/epubcn/archive/2008/11/14/66888.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Fri, 14 Nov 2008 02:56:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2008/11/14/66888.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/66888.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2008/11/14/66888.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/66888.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/66888.html</trackback:ping><description><![CDATA[
<p>先说一句题外话，上一节一开始我提到了由于.rc导致我自己写的插件不能被FF识别的问题，今天终于找到答案了。在这篇文章中：<a title="https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Plug-in_Development_Overview" href="https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Plug-in_Development_Overview">https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Plug-in_Development_Overview</a>，有这么一段话：In your development environment, make sure your language is set to "US English" and the character set to "Windows Multilingual." The resource code for this language and character set combination is 040904E4. 看来这FF还只能使用英文。</p>
<p>OK，步入正题。这一小节我来简单说一下如何为插件添加和脚本语言（如Javascript）交互的能力。我会为插件添加几个函数，供Javascript调用。</p>
<p>前面我们提到过浏览器调用插件的方法的顺序，基本上为：NP_GetEntryPoints、NP_Initialize、NPP_New、NPP_SetWindow、NPP_GetValue。在NPP_New中，我们需要创建插件对象的实例，NPP_SetWindow中，浏览器会传入插件窗口的信息，最后一个NPP_GetValue，是浏览器来获取一些插件信息的。NPP_GetValue函数的结构是这样的：</p>
<p><strong>NPError&nbsp; NPP_GetValue(NPP instance, NPPVariable variable, void *value);</strong></p>
<ul>
    <li>instance包含着插件对象实例；</li>
    <li>variable表示浏览器要获取的信息的类型;</li>
    <li>value表示返回给浏览器的值</li>
</ul>
<p><strong>浏览器会传入NPPVpluginScriptableNPObject（作为variable参数）来查询插件是否支持Scriptable功能（即和脚本语言交互的功能），在这里，我们可以利用NPN_CreateObject方法来创建一个NPObject对象，并且作为value返回给浏览器。这样，浏览器就通过这个NPObject对象和我们的插件建立了连接。当页面上Javascript调用了我们插件对象的某个方法时，浏览器会调用该NPObject对象的HasMethod方法来查询是否支持这个方法，如果支持，则会调用NPObject对象的Invoke方法，传入方法名、参数等信息。这样，我们就可以让网页上的脚本语言来执行我们编写的函数了。在Windows上，我们编写的函数就如同编写普通的应用程序一样，可以使用很多Windows API来完成许多复杂的工作。</strong></p>
<p>上面有个问题：如何创建我们自己的NPObject对象？NPN_CreateObject方法如何使用？好在Mozilla给我们提供了npruntime这个例子程序，可以让我们得以参考。</p>
<p>先来看看NPN_CreateObject方法的定义：</p>
<p>NPObject *NPN_CreateObject(NPP npp, NPClass *aClass);</p>
<p>关键在第二个参数上，我们需要提供一个NPClass指针。npruntime例子程序中是这么做的：</p>
<p>定义了一个宏DECLARE_NPOBJECT_CLASS_WITH_BASE，其作用就是定义了一个静态的NPClass对象，并且NPClass要求的所有基础方法，都由一个ScriptablePluginObjectBase类来提供。我们根据需要，来创建不同的继承于ScriptablePluginObjectBase的类（比如支持方法的类和支持属性的类），传给DECLARE_NPOBJECT_CLASS_WITH_BASE宏，这样，当浏览器管我们&#8220;要&#8221;的时候，我们就可以按照它的需要&#8220;给&#8221;它对应的对象。</p>
<p>npruntime例子中，ScriptablePluginObject是用来处理方法的，而ConstructablePluginObject是用来处理属性的。</p>
<p>&nbsp;</p>
<p><strong>如何定义一个方法（或属性）？</strong></p>
<p>1、添加一个方法（或属性）很简单，先定义一个静态NPIdentifier类型的变量，例如：</p>
<p>static NPIdentifier s_idSetArgs;</p>
<p>2、在插件对象构造函数中，使用NPN_GetStringIdentifier方法来设置该方法的名称，例如：</p>
<p>s_idSetArgs = NPN_GetStringIdentifier("SetArgs");</p>
<p>其中，SetArgs就是我们提供给脚本语言调用的方法名称。</p>
<p>3、在ScriptablePluginObject的HasMethod方法中，判断传入的方法名：</p>
<p>bool ScriptablePluginObject::HasMethod(NPIdentifier name)<br>{<br>&nbsp;&nbsp;&nbsp; if(name == s_idSetArgs)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("method name = SetArgs\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>&nbsp;&nbsp;&nbsp; }  </p>
<p>&nbsp;&nbsp;&nbsp; return false;<br>} </p>
<p>4、在ScriptablePluginObject的Invoke方法中，判断如果传入的方法名称等于我们定义的方法名，则做你想要做得事情： </p>
<p>//////////////////////////////////////////////////////////////////////////<br>///<br>/// @brief&nbsp;&nbsp;&nbsp; 如果某个方法支持（使用HasMethod检测），当页面上Javascript代码调用该方法时，会执行本函数<br>///<br>/// @param [in] name&nbsp;&nbsp;&nbsp; 方法名<br>/// @param [in] args&nbsp;&nbsp;&nbsp; 参数值（数组）<br>/// @param [in] argCount&nbsp;&nbsp;&nbsp; 参数个数<br>/// @param [in] result&nbsp;&nbsp;&nbsp; 执行后返回给调用者的结果<br>///<br>/// @return PR_TRUE表示执行成功，PR_FALSE表示失败<br>///<br>////////////////////////////////////////////////////////////////////////// </p>
<p>bool ScriptablePluginObject::Invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result) </p>
<p>{<br>&nbsp;&nbsp;&nbsp; if(name == s_idSetArgs)</p>
<p>&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里做你想要做得事情</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return PR_TRUE;</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; return PR_FALSE;</p>
<p>}</p>
<p>关于方法参数的接收，这里举个例子。比如网页上这么调用：</p>
<p>embedobj.SetArgs("name", "value");</p>
<p>在我们的方法中，就可以这么接收：</p>
<p>if(args != NULL &amp;&amp; argCount &gt;= 2)<br>{<br>&nbsp;&nbsp;&nbsp; NPVariant npvName = args[0]; //第一个参数<br>&nbsp;&nbsp;&nbsp; NPVariant npvValue = args[1]; //第二个参数<br>&nbsp;&nbsp;&nbsp; if(NPVARIANT_IS_STRING(npvName) &amp;&amp; NPVARIANT_IS_STRING(npvValue))&nbsp; //如果两者都是字符串类型（当然你还可以判断是否是其他类型）<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NPString npsName = NPVARIANT_TO_STRING(npvName); //转成NPString<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NPString npsValue = NPVARIANT_TO_STRING(npvValue);  </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(npsName.utf8characters &amp;&amp; strlen(npsName.utf8characters) &gt; 0) //限定条件，可以根据需要进行修改。这里限定第一个参数内容不能为空<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nLenName = strlen(npsName.utf8characters) + 1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nLenValue = strlen(npsValue.utf8characters) + 1;  </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARAMPAIR paramPair;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paramPair.pName = new char[nLenName];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(paramPair.pName, 0, nLenName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paramPair.pValue = new char[nLenValue];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(paramPair.pValue, 0, nLenValue);  </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(paramPair.pName, npsName.utf8characters); //将参数内存存储到我们熟悉的C<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(paramPair.pValue, npsValue.utf8characters);  </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_vecParamPair.push_back(paramPair);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>} </p>
<p>上面的代码中，PARAMPAIR就是一个简单的结构体： </p>
<p>typedef struct tagPARAMPAIR<br>{<br>&nbsp;&nbsp;&nbsp; LPTSTR pName;<br>&nbsp;&nbsp;&nbsp; LPTSTR pValue;<br>}PARAMPAIR, *PPARAMPAIR; </p>
<p>m_vecParamPair是一个vector：vector&lt;PARAMPAIR&gt; m_vecParamPair;</p>
<p>顺便说一句，上面只是代码片段，关于内存释放、vector清空等操作，由于不是这里要说的关键部分，所以没有列出。</p>
<p>OK，现在我们的插件已经可以顺利和网页进行交互工作了。</p><img src ="http://www.cppblog.com/epubcn/aggbug/66888.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2008-11-14 10:56 <a href="http://www.cppblog.com/epubcn/archive/2008/11/14/66888.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】我的Firefox插件开发之旅（6）&amp;mdash;&amp;mdash;FF插件的一些基础知识</title><link>http://www.cppblog.com/epubcn/archive/2008/11/12/66719.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Wed, 12 Nov 2008 06:40:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2008/11/12/66719.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/66719.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2008/11/12/66719.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/66719.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/66719.html</trackback:ping><description><![CDATA[
<p>上篇文章学习了npruntime的例子程序，接下来迫不及待地想实现自己的一个插件了。我决定使用VS 2005来做。</p>
<p>新建了一个名为npgnet的工程，按照npruntime例子，新建了np_entry.cpp、npn_gate.cpp、npp_gate.cpp、npgnet.def四个文件，然后新建了一个类CGnetFFPlugin，并且把例子中的关键代码添加了进来（我删除了一些cplugin类中的函数实体代码，因为我实现的功能和例子中的无关）。编译后，将生成的npgnet.dll放到FF的plugins目录下，然后在地址栏键入about:plugins，我靠，竟然没有我的插件！怎么回事？三个导出函数我都按照标准写了啊？比较了一下文件，我的工程没有添加.rc和resource.h，可能是这个原因。</p>
<p>回到VS 2005，在资源面板添加了一个VERSION资源项，修改ProductName等资源项以后，和npruntime例子比较了一下，还差MIMEType。这个东东很重要，这个给我的感觉就是FF插件的身份证，FF就是靠这个东东来匹配和识别你的插件的。但是我不知道VS 2005中怎么添加一个VERSION的键值，所以我只好用EditPlus打开npgnet.rc，手动添加了MIMEType：application/mozilla-npgnet-scriptable-plugin。OK，现在.rc和resource.h都欧了，再编译，将生成的npgnet.dll放到FF的plugins目录下，然后在地址栏键入about:plugins，我靠，竟然还是没有我的插件！真费解啊！</p>
<p>头大&#8230;&#8230;接下来我进行了一系列的代码比较和尝试，失败了N多次，这里就省略不说了。最后发现原因原来在这个.rc上面。我的这个.rc是在VS 2005中使用菜单命令添加的，默认语言是简体中文，而npruntime例子是英文，用文件比较工具比较了一下，codepage和部分代码的位置都不太一样。其实只要把npruntime的这个.rc文件替换我的这个，然后编译输出的dll，FF就可以识别了！究竟是什么原因呢？是我的.rc缺少了些什么东西？还是FF只能识别英文的.rc？先不打算研究那么多了，至少我的插件的关键点不在这个上面，后面我还有很多事情需要去做。只要能让FF认出来，那就好。</p>
<p>既然决定要写插件，就要先理解插件的概念，在这个页面上有很详细的介绍：<a title="https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Plug-in_Basics" href="https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Plug-in_Basics">https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Plug-in_Basics</a></p>
<p>下面的文字是我的一些阅读笔记和体会：</p>
<p><strong>一、插件的加载过程</strong></p>
<p>当一个页面打开时，如果该页面上有嵌入一个插件，浏览器将会做以下事情：</p>
<ul>
    <li>通过MIMEType检查是否有匹配插件</li>
    <li>加载插件代码到内存</li>
    <li>初始化插件</li>
    <li>创建一个新的插件实例</li>
</ul>
<p>插件可以在一个页面上被实例多个对象，也可以在同一时刻在不同的窗口中被实例化。当页面被关闭时，插件的实例就会被销毁。当最后一个实例被删除后，插件代码就会从内存中被卸载掉。</p>
<p>下面是插件内的函数调用过程：</p>
<ul>
    <li>如果插件是首次被载入内存，浏览器会调用插件的<strong>NP_Initialize</strong>方法。为了方便起见，所有的插件定义函数以&#8220;NPP&#8221;开头，所有的浏览器定义函数以&#8220;NPN&#8221;开头。</li>
    <li>当浏览器创建插件实例时，会调用<strong>NPP_New</strong>方法。</li>
    <li>当插件实例被删除时（如关闭页面、关闭窗口），会调用<strong>NPP_Destroy</strong>方法。</li>
    <li>当最后一个实例被删除，插件从内存中卸载时，会调用<strong>NP_Shutdown</strong>方法。</li>
</ul>
<p><strong>二、插件检测</strong></p>
<p>可以使用Javascript来检测一个插件是不是已经安装了，下面是测试代码：<br>function DetectFFPlugin()<br>{<br>&nbsp;&nbsp;&nbsp; var mimetype = navigator.mimeTypes["application/mozilla-npgnet-scriptable-plugin"];<br>&nbsp;&nbsp;&nbsp; if(mimetype)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var plugin = mimetype.enabledPlugin;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(plugin)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; document.writeln("Plugin had been installed and be enabled.");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; document.writeln("Sorry, Plugin has NOT been installed.");<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>嗯，看到这里，觉得这个检测很有用。当检测用户尚未安装时，可以指导用户到哪哪哪去下载安装（转向一个漂亮点儿的页面），当检测已经安装了，就动态加载插件代码。不错。：）</p>
<p><strong>三、插件结构概述</strong></p>
<p>一个插件中的方法分为插件方法（Plug-in Methods）和浏览器方法（Browser Methods）。插件方法是你在插件中自己去执行的那些方法，以NPP为前缀命名。浏览器方法是被Gecko所执行的那些方法，以NPN为前缀命名。数据结构（Data Structures）以NP开头。</p>
插件可分为有窗口和无窗口两种，不过文章中建议使用有窗口的，说这样会更稳定和易于控制。另外文中提到了可以将插件作为页面的一部分，并且可以使用HTML代码来控制插件的显示与否。<br><br>有两种方式可以使一个插件不可见：<br><br>1、如果你使用embed标签，可以使用其hidden属性，例如：&lt;embed src="audiplay.aiff" type="audio/x-aiff" hidden="true"&gt;<br>2、如果你是用object标签，由于它没有hidden属性，你可以用CSS来完成隐藏：<br><br>object <br>{ <br>&nbsp;&nbsp;&nbsp; visibility: visible; <br>} <br>object.hiddenObject <br>{ <br>&nbsp;&nbsp;&nbsp; visibility: hidden !important; <br>&nbsp;&nbsp;&nbsp; width: 0px&nbsp; !important; <br>&nbsp;&nbsp;&nbsp; height: 0px&nbsp; !important; <br>&nbsp;&nbsp;&nbsp; margin: 0px&nbsp; !important; <br>&nbsp;&nbsp;&nbsp; padding: 0px&nbsp; !important; <br>&nbsp;&nbsp;&nbsp; border-style: none&nbsp; !important; <br>&nbsp;&nbsp;&nbsp; border-width: 0px&nbsp; !important; <br>&nbsp;&nbsp;&nbsp; max-width: 0px&nbsp; !important; <br>&nbsp;&nbsp;&nbsp; max-height: 0px&nbsp; !important; <br>} <br><br>
<p>&lt;object data="audiplay.aiff" type="audio/x-aiff" <strong>class="hiddenObject"</strong>&gt;&lt;/object&gt;
</p>
<p>接下来文中介绍了object这个标签的使用。并且给了一个例子来说明ActiveX和插件如何融为一体来使用。</p>
<p>最后面的部分是对object和embed两种标签的各种属性的说明和举例。</p>
<p>值得一提的是，对于object和embed两种标签都可以在页面上嵌入一个插件。如何取舍呢？文章中有这么一段话：</p>
<p>Though the <code>object</code> element is the preferred way to invoke plug-ins, the <code>embed</code> element can be used for backward compatibility with Netscape 4.x browsers, and in cases where you specifically want to prompt the user to install a plug-in, because the default plug-in is only automatically invoked when you use the <code>embed</code> element.</p>
<p>意思是说：尽管object是推荐使用的调用插件的方式，embed也可嵌入插件（Netscape 4.x以上的浏览器），但如果你想在用户没有安装插件时，提示他进行安装，那么就应该选择用embed，因为FF的默认插件系统仅仅在你使用embed标签的时候，才会自动帮助你完成这种提示用户安装的效果。</p>
<p>我看过以后的感觉是，object使用起来似乎比embed要复杂，起码针对FF这个浏览器是这样，虽然他是HTML W3C的标准。多数情况下使用embed就可以了，何况现在谁还在用Netscape 4.x以下版本的浏览器啊，您说是不是？：）</p>
<p>OK，通过这几天的学习，终于对FF的插件编写有了一个初步的感性认识。到目前为之一切还比较顺利。</p><img src ="http://www.cppblog.com/epubcn/aggbug/66719.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2008-11-12 14:40 <a href="http://www.cppblog.com/epubcn/archive/2008/11/12/66719.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】我的Firefox插件开发之旅（5）&amp;mdash;&amp;mdash;编译和测试第一个Plugin例子：npruntime</title><link>http://www.cppblog.com/epubcn/archive/2008/11/11/66612.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Tue, 11 Nov 2008 07:47:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2008/11/11/66612.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/66612.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2008/11/11/66612.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/66612.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/66612.html</trackback:ping><description><![CDATA[
<p>前几天一直在忙乎着研究和阅读XUL和FF的Extension相关资料，今天突然发现，我要做得事情似乎不是用Extension来实现的。因为原来的应用是一个ActiveX，网页会将一些参数通过ActiveX控件传递进来，而ActiveX接到这些参数以后，会和服务器进行一些数据交互，最后调起本地的执行程序。似乎我走了一些弯路，方向不对。我要做得事情应该是编写一个Plugin，而非Extension。</p>
<p>及时修正了下一步的研究计划，那么就让我们先来编译和测试Mozilla提供的一个小例子吧。原文连接在这里：</p>
<p><a title="https://developer.mozilla.org/En/Compiling_The_npruntime_Sample_Plugin_in_Visual_Studio" href="https://developer.mozilla.org/En/Compiling_The_npruntime_Sample_Plugin_in_Visual_Studio">https://developer.mozilla.org/En/Compiling_The_npruntime_Sample_Plugin_in_Visual_Studio</a>。文章中是以VS2003举例，我这里以VC6来进行测试，并且将步骤中需要注意的地方特别说明了一下。</p>
<p>1、先到这里下载相关源码：<a title="http://mxr.mozilla.org/seamonkey/source/modules/plugin/samples/npruntime/" href="http://mxr.mozilla.org/seamonkey/source/modules/plugin/samples/npruntime/">http://mxr.mozilla.org/seamonkey/source/modules/plugin/samples/npruntime/</a>。不知道为什么Mozilla只提供了页面形式，没有打个包，害得我得一个个文件下载和保存，郁闷。</p>
<p>2、在VC6中新建一个Win32 Dynamic-Link Library工程，取名&#8220;nprt&#8221;。注意：建议工程以小写np开头，并且长度不超过8个字符，这样以后就会省事很多。</p>
<p>3、下一步，选择&#8220;An empty DLL project&#8221;，然后&#8220;Finish&#8221;。</p>
<p>4、将刚才下载的源码添加到工程中来。test.html不用添加，nprt.def建议也添加进来。</p>
<p>5、现在还不能编译，否则会出很多错误。打开Project Settings，转到C/C++标签页，在Category中选择Preprocessor，在Preprocessor Definitions中最后面添加：,XP_WIN32,MOZILLA_STRICT_API,XPCOM_GLUE,XP_WIN,_X86_。注：如果你使用VS 2005，需要添加全部的定义：WIN32;_WINDOWS;NPRT_EXPORTS;XP_WIN32;MOZILLA_STRICT_API;XPCOM_GLUE;XP_WIN;_X86_</p>
<p>6、在Additional include directories下面添加XULRunner SDK的include路径，可以是绝对路径，也可以是相对路径，看你当初怎么解压的了。例如：..\..\xulrunner-sdk\include</p>
<p>7、在Category中选择Precompiled Headers，选择Not using precompiled headers，OK，关闭Project Settings对话框。打开npp_gate.cpp，将下面的代码注释掉：<br>jref NPP_GetJavaClass (void)<br>{<br>&nbsp; return NULL;<br>}</p>
<p>8、编译！&#8230;&#8230;我靠，有错：Fatal error C1083: Cannot open include file: 'npapi.h': No such file or directory。我可是严格按照教程上面写的去做得啊。</p>
<p>9、在xulrunner-sdk目录下搜索了一下npapi.h，原来在xulrunner-sdk\sdk\include下面，这好办，多加一条包含路径不就欧了？仿照第6步，添加该目录；</p>
<p>10、编译！OK，过了。</p>
<p>11、到输出目录下将nprt.dll复制到FF安装目录的plugins目录下，例如：C:\Program Files\Mozilla Firefox\plugins\</p>
<p>12、如果此时FF开着也没关系，不用关（这点很不错）。在地址栏键入about:plugins，看看是不是有一个npruntime scriptable example plugin，如果有，那就表示欧了，FF认出了我们的插件；</p>
<p>13、在FF中打开test.html，嗯？怎么还提示安装缺失插件？用EditPlus打开test.html，噢，原来有这么一句：&lt;embed type="application/x-java-mozilla-npruntime-scriptable-plugin" style="display: block; width: 50%; height: 100px;"&gt;。因为我们刚才没有添加名字为x-java-mozilla-npruntime-scriptable-plugin的插件，所以当然认不出来啦。</p>
<p>14、随便点一下页面上的按钮，看看简单的交互行为。</p>
<p>&nbsp;</p>
<p>OK，第一个例子还算顺利，比想象中的要顺利。下面就该研究一下代码了，看看FF的插件和ActiveX的区别到底有多大。</p>
<p>附一些参考资料：<br><a title="http://xinsync.xju.edu.cn/index.php/archives/2124" href="http://xinsync.xju.edu.cn/index.php/archives/2124">http://xinsync.xju.edu.cn/index.php/archives/2124</a><br><a title="http://mqjing.blogspot.com/2008/09/plugin-firefox-plugin.html" href="http://mqjing.blogspot.com/2008/09/plugin-firefox-plugin.html">http://mqjing.blogspot.com/2008/09/plugin-firefox-plugin.html</a></p><img src ="http://www.cppblog.com/epubcn/aggbug/66612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2008-11-11 15:47 <a href="http://www.cppblog.com/epubcn/archive/2008/11/11/66612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】我的Firefox插件开发之旅（4）&amp;mdash;&amp;mdash;XULRunner的一个例子</title><link>http://www.cppblog.com/epubcn/archive/2008/11/10/66502.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Mon, 10 Nov 2008 03:54:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2008/11/10/66502.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/66502.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2008/11/10/66502.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/66502.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/66502.html</trackback:ping><description><![CDATA[
<p>上一节写了一个Extension，添加了一个按钮在FF3的工具栏上。接下来我准备在这个基础上添加一个功能，点击按钮，读取本地磁盘上一个文件的内容，并显示出来。怎么做呢？用Javascript吗？因为我最终的目标是从服务器上下载文件，也可能会传输本地文件到服务器上，用Javascript访问本地文件有诸多限制，而且也无法完成复杂的功能。所以最好是能够调用我编写的 DLL那就最好不过了。怎么做呢？还是在Mozilla网站上找找看吧。</p>
<p>在Mozilla网站上看到，可以自己编写Component来完成一些自定义操作。需要首先安装Gecko SDK（现在叫XULRunner SDK），Windows上有两个版本，1.8是for FF1.5/2.0的，1.9是for FF3.0的，由于我机器上安装的是FF3.0，那么就先下载1.9吧，与FF1.5/2.0兼容的问题以后再说。</p>
<p>下载了XULRunner SDK 1.9，解压到本地后，在环境变量里配置了PATH到xulrunner-sdk的bin目录，以便可以在command prompt下直接运行xulrunner.exe。OK，环境配置完毕，下面来个写个小例子吧。Mozilla提供了一个短小精悍的例子程序，在这里：<a title="https://developer.mozilla.org/en/Getting_started_with_XULRunner" href="https://developer.mozilla.org/en/Getting_started_with_XULRunner">https://developer.mozilla.org/en/Getting_started_with_XULRunner</a></p>
<p>这篇文章一步一步教我们编写一个HelloWorld程序，写的很清楚。不过做完这个例子，我有几个疑问：<br>1、在上一节我们写的Extension中，chrome.manifest这个文件是放在根目录的（与chrome目录同级），为什么这里把它放在了chrome目录里面呢？能否保持和Extension相同？我简单尝试了一下，并修改了chrome.manifest里面content所指向的目录，然后运行了一下，什么都没发生，没有看到正常运行时所弹出的对话框，看来还是解析不正确，是不是xulrunner必须要求chrome.manifest在chrome目录下面呢？<br>2、application.ini中App节的ID，和Extension的ID（通常是一个GUID）有无关联呢？<br>3、调用xulrunner.exe以后，会产生两个目录：extensions和updates，这两个目录是干什么用的呢？</p>
<p>另外这里需要特别说明一点：在运行xulrunner去执行application.ini时，千万不能丢掉.exe，即不能写/&gt;xulrunner application.ini，必须是/&gt;xulrunner.exe application.ini，否则会弹出couldn't parse的错误提示，具体是什么原因我也不清楚。</p>
<p>另外，这里还有一篇关于xulrunner的教程，解释了一些概念性的东西：<a title="http://blogs.acceleration.net/ryan/archive/2005/05/06/1073.aspx" href="http://blogs.acceleration.net/ryan/archive/2005/05/06/1073.aspx">http://blogs.acceleration.net/ryan/archive/2005/05/06/1073.aspx</a></p>
<p>写完这个例子，感觉方向好像不太对，xulrunner好像主要还是做界面，怎么做组件呢？怎么访问本地磁盘文件、甚至系统注册表？在Mozilla的开发者页面上又看到一个东东：XPCOM，开头的一段介绍文字是这样的：</p>
<p>XPCOM is a cross platform component object model, similar to Microsoft COM. It has multiple language bindings, letting the XPCOM components be used and implemented in JavaScript, Java, and Python in addition to C++. Interfaces in XPCOM are defined in a dialect of IDL called XPIDL.  </p>
<p>XPCOM itself provides a set of core components and classes, e.g. file and memory management, threads, basic data structures (strings, arrays, variants), etc. The majority of XPCOM components is not part of this core set and is provided by other parts of the platform (e.g. Gecko or Necko) or by an application or even by an extension. </p>
<p>大概的意思是说XPCOM类似于微软的COM组件概念，它可以定义一些接口，可以在JS、Java、Python以及C++中使用。哈哈，看来这个才是我想要的东西。OK，那接下来我就来研究一下这个东东吧。下一节争取能完成我一开始提到的功能。</p><img src ="http://www.cppblog.com/epubcn/aggbug/66502.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2008-11-10 11:54 <a href="http://www.cppblog.com/epubcn/archive/2008/11/10/66502.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】我的Firefox插件开发之旅（3）&amp;mdash;&amp;mdash;我的第一个扩展</title><link>http://www.cppblog.com/epubcn/archive/2008/11/08/66286.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Fri, 07 Nov 2008 16:55:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2008/11/08/66286.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/66286.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2008/11/08/66286.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/66286.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/66286.html</trackback:ping><description><![CDATA[
<p><strong>（原创作品，转载请注明链接）</strong></p>
<p>简单知道了XUL，迫不及待地想立即编写一个插件，哪怕什么事情都不做也好。O(&#8745;_&#8745;)O</p>
<p>通过这个页面<a title="https://developer.mozilla.org/en/Building_an_Extension" href="https://developer.mozilla.org/en/Building_an_Extension">https://developer.mozilla.org/en/Building_an_Extension</a>，可以找到编写一个插件必须要做得一些事情，写的很清楚。最后产生的目录和文件结构是这个样子：<br>install.rdf<br>chrome.manifest<br>chrome<br>&nbsp; |--content<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--overlay.xul （我准备在这里编写代码，在FF的工具栏上添加一个按钮）<br>&nbsp; |--locale<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--en-US<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--sample.dtd<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--zh-CN<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--sample.dtd<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--zh-TW<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--sample.dtd<br>&nbsp; |--skin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--classic<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--sampleicon.png<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--smallicon.png<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |--default.css （界面显示的样式表，今后可能会用到）</p>
<p><br>上面文件中的install.rdf、chrome.manifest基本上用例子中的就好了，dtd文件里面是界面文字，这个可以模仿其他插件编写。<br>overlay.xul我准备添加一段代码，用来在FF工具栏上添加一个按钮。skin下面的png是准备在工具栏上添加的按钮的图标。</p>
<p>OK，把上面整个目录用zip打个包，改后缀名为xpi，拖放到FF3中，提示尚未验证作者、是否继续安装。这个先不管它，以后再研究。安装以后，重启FF3，哈哈，写的第一个Extension成功安装了！只不过overlay.xul里面什么都没写，所以还没有视觉上的成就感。下面开始添加overlay.xul中的代码。</p>
<p>怎么在工具栏上添加按钮呢？感谢Mozilla提供的文档，专门有一篇文章是讲这个地：<a title="https://developer.mozilla.org/en/Creating_toolbar_buttons" href="https://developer.mozilla.org/en/Creating_toolbar_buttons">https://developer.mozilla.org/en/Creating_toolbar_buttons</a>。文章里面讲的非常清楚，我这里就不废话了。不过有两点需要注意一下：<br>1、样式表中的ID和toolbarbutton的id一定要保持一致；<br>2、按钮的label和tooltiptext可以直接添加文字，但如果使用了中文，有可能会显示乱码（至少在我的FF3上是这样）；<br>3、按钮的图标一定要大小两种（24x24、16x16）都提供；<br>4、label和tooltiptext可以使用dtd中定义的文字，但必须注意：dtd文件必须存为UTF-8编码，否则会导致按钮显示不出来！</p>
<p>在FF3的定制工具栏中，有图标，但下方没有文字，好像是我哪里忘记添加文字了，一会儿看看去&#8230;&#8230;</p>
<p>好了，我的第一个FF插件就写好了，不过现在只是在工具栏上添加了一个按钮而已，什么事情都没做，下一次我们添加一些行为给它。</p>
<p>以下附上几个关键文件的内容：<br><strong></strong></p>
<h5><strong>一、install.rdf</strong></h5>
<p><strong><br></strong>&lt;?xml version="1.0"?&gt;<br>&lt;RDF xmlns="<a href="http://www.w3.org/1999/02/22-rdf-syntax-ns#%22">http://www.w3.org/1999/02/22-rdf-syntax-ns#"</a> xmlns:em="<a href="http://www.mozilla.org/2004/em-rdf#%22">http://www.mozilla.org/2004/em-rdf#"</a>&gt;<br>&nbsp;&nbsp;&nbsp; &lt;Description about="urn:mozilla:install-manifest"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:id&gt;{859606AC-AFFE-4691-82C5-FA0148A7E2D4}&lt;/em:id&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:version&gt;1.0&lt;/em:version&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:type&gt;2&lt;/em:type&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:name&gt;MeetMePlus&lt;/em:name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:description&gt;Anywhere, anytime to starting a conferencing&lt;/em:description&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:creator&gt;G-NET&lt;/em:creator&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:iconURL&gt;chrome://meetmeplus/skin/gnet_32.png&lt;/em:iconURL&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:homepageURL&gt;<a href="http://www.meetmeplus.com/">http://www.meetmeplus.com/</a>&lt;/em:homepageURL&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:targetApplication&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Description&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:id&gt;{ec8030f7-c20a-464f-9b0e-13a3a9e97384}&lt;/em:id&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:minVersion&gt;1.5&lt;/em:minVersion&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;em:maxVersion&gt;3.0.*&lt;/em:maxVersion&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Description&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/em:targetApplication&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/Description&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&lt;/RDF&gt;</p>
<h5><strong>二、chrome.manifest</strong></h5>
<p>overlay&nbsp;&nbsp;&nbsp; chrome://browser/content/browser.xul&nbsp;&nbsp;&nbsp; chrome://meetmeplus/content/overlay.xul<br>content&nbsp;&nbsp;&nbsp; meetmeplus&nbsp;&nbsp;&nbsp; chrome/content/<br>style&nbsp;&nbsp;&nbsp; chrome://global/content/customizeToolbar.xul&nbsp;&nbsp;&nbsp; chrome://meetmeplus/skin/default.css<br>skin&nbsp;&nbsp;&nbsp; meetmeplus&nbsp;&nbsp;&nbsp; classic/1.0&nbsp;&nbsp;&nbsp; chrome/skin/classic/<br>locale&nbsp;&nbsp;&nbsp; meetmeplus&nbsp;&nbsp;&nbsp; zh-CN&nbsp;&nbsp;&nbsp; chrome/locale/zh-CN/
</p>
<h5><strong>三、overlay.xul</strong></h5>
<p>&lt;?xml version="1.0"?&gt;<br>&lt;!DOCTYPE overlay SYSTEM "chrome://meetmeplus/locale/overlay.dtd"&gt;<br>&lt;?xml-stylesheet href="chrome://meetmeplus/skin/default.css" type="text/css"?&gt;
</p>
<p>&lt;overlay id="mmp-overlay" xmlns="<a href="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul%22">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"</a>&gt;<br>&nbsp;&nbsp;&nbsp; &lt;!-- Firefox toolbar --&gt;<br>&nbsp;&nbsp;&nbsp; &lt;toolbarpalette id="BrowserToolbarPalette"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;toolbarbutton id="meetmeplus-button" type="menu-button" <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="toolbarbutton-1 chromeclass-toolbar-additional"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;menupopup&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;menuitem label="&amp;mmp.gotohome;" tooltiptext="&amp;mmp.gotohome.tooltip;" image="chrome://meetmeplus/skin/option_16.png" class="menuitem-iconic"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;menuseparator/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;menuitem label="&amp;mmp.option;" tooltiptext="&amp;mmp.option.tooltip;" image="chrome://meetmeplus/skin/option_16.png" class="menuitem-iconic"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/menupopup&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/toolbarbutton&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/toolbarpalette&gt;<br>&lt;/overlay&gt;
</p>
<h5><strong>四、overlay.dtd</strong></h5>
<p>&lt;!ENTITY mmp.gotohome "访问G-NET MeetMePlus"&gt;<br>&lt;!ENTITY mmp.gotohome.tooltip "访问G-NET MeetMePlus网站"&gt;<br>&lt;!ENTITY mmp.option "选项"&gt;<br>&lt;!ENTITY mmp.option.tooltip "自定义G-NET MeetMePlus的工作方式"&gt;</p><img src ="http://www.cppblog.com/epubcn/aggbug/66286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2008-11-08 00:55 <a href="http://www.cppblog.com/epubcn/archive/2008/11/08/66286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】我的Firefox插件开发之旅（2）&amp;mdash;&amp;mdash;XUL是什么？</title><link>http://www.cppblog.com/epubcn/archive/2008/11/07/66210.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Fri, 07 Nov 2008 05:50:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2008/11/07/66210.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/66210.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2008/11/07/66210.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/66210.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/66210.html</trackback:ping><description><![CDATA[
<p>What is XUL？这个页面给出了详细的介绍：<a title="http://www.xulplanet.com/tutorials/whyxul.html" href="http://www.xulplanet.com/tutorials/whyxul.html">http://www.xulplanet.com/tutorials/whyxul.html</a>。</p>
<p>看完后，了解了XUL原来是一个支持多种WEB技术的、基于XML的界面开发语言。它既可以在远程执行，也可以安装到本地执行。</p>
<p>在XUL中内置了很多界面元素，如菜单、按钮、分页等等，这样就不需要自己编写很多JS来维护和控制很多界面元素了。而且，这些界面是按照当时的OS外观来展现的，比如同一个按钮，在MacOS上和Windows上看起来就不一样。另外XUL也允许自己使用JS和CSS来定制自己的个性化界面。总之一句话，XUL的主要作用就是用来展现Extension的用户交互界面的。</p>
<p>OK，知道了XUL是什么以后，那么怎么学习它的用法呢？文章最下方适时地给出了一个连接：begin the XUL tutorial，还挺人性化:) 我点~~~</p>
<p>教程很多，很强大。看来一时半会儿全搞清楚是不可能的了。慢慢来吧。</p>
<p>哦对了，还发现一个在线的XUL编辑器，把XUL代码粘进去，下面可以实时地显示界面。不过不能引用外部脚本，否则就出错。链接是：<a title="http://ted.mielczarek.org/code/mozilla/xuledit/xuledit.xul" href="http://ted.mielczarek.org/code/mozilla/xuledit/xuledit.xul">http://ted.mielczarek.org/code/mozilla/xuledit/xuledit.xul</a>。</p>
<p>&nbsp;</p>
<p>先写这些，准备开始阅读XUL教程了&#8230;&#8230;</p><img src ="http://www.cppblog.com/epubcn/aggbug/66210.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/epubcn/" target="_blank">深蓝色系统</a> 2008-11-07 13:50 <a href="http://www.cppblog.com/epubcn/archive/2008/11/07/66210.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>