﻿<?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++博客-我的玻璃盒子-随笔分类-Firefox开发</title><link>http://www.cppblog.com/epubcn/category/8842.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 11 Aug 2009 10:56:15 GMT</lastBuildDate><pubDate>Tue, 11 Aug 2009 10:56:15 GMT</pubDate><ttl>60</ttl><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>2</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>1</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>1</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>3</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>0</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><item><title>【原创】我的Firefox插件开发之旅（1）&amp;mdash;&amp;mdash;从零开始</title><link>http://www.cppblog.com/epubcn/archive/2008/11/07/66206.html</link><dc:creator>深蓝色系统</dc:creator><author>深蓝色系统</author><pubDate>Fri, 07 Nov 2008 05:26:00 GMT</pubDate><guid>http://www.cppblog.com/epubcn/archive/2008/11/07/66206.html</guid><wfw:comment>http://www.cppblog.com/epubcn/comments/66206.html</wfw:comment><comments>http://www.cppblog.com/epubcn/archive/2008/11/07/66206.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/epubcn/comments/commentRss/66206.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/epubcn/services/trackbacks/66206.html</trackback:ping><description><![CDATA[
<p>准备做一个Firefox插件，用来接收从WEB页面传递的参数，根据这些参数从服务器上下载一些文件到本地，并调起本地的一个应用程序。</p>
<p>以前在IE中是使用一个ActiveX来实现的。FF的插件从来没有做过，不知道将来会遇到多少困难。</p>
<p>&nbsp;</p>
<p>在网上发现一个页面：<a title="http://ted.mielczarek.org/code/mozilla/extensionwiz/" href="http://ted.mielczarek.org/code/mozilla/extensionwiz/">http://ted.mielczarek.org/code/mozilla/extensionwiz/</a>，它提供了一个FF扩展的生成向导，填写完必要信息后，会生成一个zip文件。之后我改名为xpi后，丢到我的FF 3.0中，提示不正确的安装包。看来这个向导针对FF3还有些问题。具体问题是什么？现在还不清楚。让我来继续寻找资料&#8230;&#8230;</p>
<p>&nbsp;</p>
<p>在Mozilla网站上了解到，FF的Extension和Plugin是两种概念的东西：</p>
<p>Extension就是一个zip包，里面有规定的一些必要文件。这个可以下载几个插件看一下他们的目录结构就好了。我下载了一个 QuickNote，看了一下，主要包括一个install.rdf（安装包相关信息和文件资源路径等配置）、chrome.manifest（设置各种XUL文件路径以及其他的一些资源文件路径）、chrome文件夹（里面放着插件的所有源文件），不过chrome文件夹里面的文件我还没有过多研究。</p>
<p>Plugin好像是另外一码事了，在Mozilla Developer Center的Plugin开发介绍文中有这么一句：Plugins are different from extensions, which modify or enhance the functionality of the browser itself. Plugins are also different from search plugins, which plug additional search engines in the search bar. （插件与扩展不同，它更改或者改善了浏览器自身的功能。插件与搜索插件又不同，搜索插件在搜索工具栏上添加了额外的搜索引擎。）</p>
<p>我的理解，插件可以让你在FF中使用自己的View来展示、用自己编写的二进制文件来做某些事情，不仅仅是利用FF自身支持的一些特性和功能。而扩展相对来说就不需要这些东西，只利用FF的开发API就好了。</p>
<p>&nbsp;</p>
<p>这样看来，要实现我开始提到的需求，似乎可以开发一个Extension就可以了。Foxmarks Bookmark Synchronizer（FBS）也差不多是我的需求这种感觉：将本地某些数据上传至服务器，从服务器同步下载一些数据到本地。FBS既然是一个扩展能够实现，那么看来我暂时不用研究Plugin了，呵呵。</p>
<p>&nbsp;</p>
<p>OK，有了大概的目标。下面开始制订学习计划！</p>
<p>通过研究别人写的Extension，里面有很多js、css、images、html，这些应该还好理解，但是多了一些后缀名为xul的文件。这是什么东西？看来想开发Extension，这个文件需要好好研究一下。</p>
<p>因此，我的第一个学习计划就是搞清楚XUL是什么，什么地方要用XUL，以及怎么写XUL？</p>
<p>&nbsp;</p>
<p>先说到这里，下一小节我来写一些XUL的学习历程。</p><img src ="http://www.cppblog.com/epubcn/aggbug/66206.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:26 <a href="http://www.cppblog.com/epubcn/archive/2008/11/07/66206.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>