1.XPCOM的很多东西都和COM的内容很像。当然也就在类型上有很多麻烦的地方,在此也不再啰嗦,读者自己研究尝试。
这里只是做个简单的示例,用于XPCOM回调JS内容。
准备:
1.下载python2.7.3(高的版本貌似有点问题,木有深入研究过),并设置环境变量,网上很多,不再说。(加入ClassPath中即可)
2.在cmd下输入python+回车,出现下图,表示成功
3.下载xulrunner-sdk.zip。
4.建立模板工程。下载setup.js,进入setup.js目录,在cmd下,setup.js回车即可安装。setup.js代码如下。(注意暂时此setup.js只支持VS2010)
setup.js的代码如下:
main();
function main() {
var debug = false;
// Create shell object
var shell = WScript.CreateObject("WScript.Shell");
var fso = WScript.CreateObject("Scripting.FileSystemObject");
// 当前目录
var strCurrentDir = "";
if (WScript.ScriptFullName.lastIndexOf("\\") != -1) {
strCurrentDir = WScript.ScriptFullName.substring(0, WScript.ScriptFullName.lastIndexOf("\\")+1);
}
var strSourceFolder = fso.BuildPath(strCurrentDir, "XPCOMWizard");
if (debug) {
WScript.Echo("Source: " + strSourceFolder);
}
if (!fso.FolderExists(strSourceFolder)) {
WScript.Echo("ERROR: Cannot find Wizard folder (should be: " + strSourceFolder + ")");
return ;
}
// vcprojects目录
var strProductDir = null;
try {
var strVC10Key = "HKLM\\Software\\Microsoft\\VisualStudio\\10.0\\Setup\\VC\\ProductDir";
strProductDir = shell.RegRead(strVC10Key);
}
catch(e) {
try
{
var strVC10Key_x64 ="HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\10.0\\Setup\\VC\\ProductDir";
strProductDir = shell.RegRead(strVC10Key_x64);
}
catch(e)
{
WScript.Echo("ERROR: Cannot find where Visual Studio 10.0 is installed.");
return;
}
}
var strDestFolder = fso.BuildPath(strProductDir, "vcprojects");
if (debug) {
WScript.Echo("Destination: " + strDestFolder);
}
if (!fso.FolderExists(strDestFolder)) {
WScript.Echo("ERROR: Cannot find destination folder (should be: " + strDestFolder + ")");
return;
}
// 拷贝配置文件
try {
fso.CopyFile(fso.BuildPath(strSourceFolder, "XPCOMWizard.ico"),
fso.BuildPath(strDestFolder, "XPCOMWizard.ico"));
fso.CopyFile(fso.BuildPath(strSourceFolder, "XPCOMWizard.vsz"),
fso.BuildPath(strDestFolder, "XPCOMWizard.vsz"));
} catch(e) {
var strError = "no info";
if (e.description.length != 0)
strError = e.description;
WScript.Echo("ERROR: Cannot copy file (" + strError + ")");
return;
}
// Create XPCOM folder
try {
var strDestXPCOMFolder = fso.BuildPath(strDestFolder, "XPCOM");
if (!fso.FolderExists(strDestXPCOMFolder))
fso.CreateFolder(strDestXPCOMFolder);
if (debug) {
WScript.Echo("XPCOM Folder: " + strDestXPCOMFolder);
}
fso.CopyFile(fso.BuildPath(strSourceFolder, "XPCOMWizard.vsdir"),
fso.BuildPath(strDestXPCOMFolder, "XPCOMWizard.vsdir"));
} catch(e) {
var strError = "no info";
if(e.description.length != 0)
strError = e.description;
WScript.Echo("ERROR: Cannot create XPCOM folder (" + strError + ")");
return;
}
// Copy File
try {
var strDestFolder = fso.BuildPath(strProductDir, "VCWizards");
if (!fso.FolderExists(strDestFolder))
fso.CreateFolder(strDestFolder);
strDestFolder = fso.BuildPath(strDestFolder, "AppWiz");
if (!fso.FolderExists(strDestFolder))
fso.CreateFolder(strDestFolder);
strDestFolder = fso.BuildPath(strDestFolder, "XPCOMWizard");
if (!fso.FolderExists(strDestFolder))
fso.CreateFolder(strDestFolder);
if (debug) {
WScript.Echo("XPCOMWizard Folder: " + strDestFolder);
}
fso.CopyFolder(strSourceFolder, strDestFolder);
} catch(e) {
var strError = "no info";
if (e.description.length != 0)
strError = e.description;
WScript.Echo("ERROR: Cannot copy XPCOMWizard folder (" + strError + ")");
return;
}
WScript.Echo("XPCOMWizard Wizard successfully installed!");
}
这样就可以在VS中直接建立XPCOM的模板项目。
5.打开VS2010,在VS2010中,新建项目,如下图向导:
选好工程目录,然后点确定。
6.选择XULRUNNER的sdk包。如下图:
7.完成。然后自动生成的工程如下:
其中重点关注的是图中
标号1,是接口的声明和被外部调用的方法。变成后,单独编译此文件,可以自动生成相应的头文件和实现文件。
标号3,是外部调用的实现
标号2,是测试的js和js调用
标号4,是测试时要改的ID好,防止缓存,每次调JS测试时都要改ID号。否则测试不成功。
8.建立js回调的IDL,js回调,也就是XPCOM的计算结果写到JS中,让页面来调用,实现C++和JS的交互。
//这里的UUID可以通过VS【工具->创建GUID】自动生成
[scriptable, uuid(B62F393E-5122-4C4F-B189-5C69065155C9)]
interface IJSCallBack: nsISupports
{
//这里的第一参数是标识,不能去掉,不然js回调不成功,一般默认的第一个标识的值默认为0
//对于数据的结果,string类型其实不是XPCOM的类型,当遇到中文的时候往往会乱码,后面详细说
//怎样转GBK都UTF8在页面上显示
boolean call(in long bogus,in string aData);
};
[scriptable, uuid(671285FA-0055-438D-9F06-3169D99CF859)]
interface IXPCOMWizard55: nsISupports
{
void Hello();
//对于回调的JS直接用上面生成的接口作为输入类型就可以。
//对于输出的参数,可以用out,但是在js中传入,一定要传入一个数组,也就是类型地址,才能正确的返回
//当然要是觉得麻烦,也可以通过返回类型来做这个传出值。如下面:
//long Sum(in long nFirst,in long nSecond,in IJSCallBack jsCallBack);
void Sum(in long nFirst,in long nSecond,in IJSCallBack jsCallBack,out long nResult);
};
完成IDL后,直接编译就可以。会自动生成相应的接口。
相应实现的代码如下:
/**
* @brief Say hello
*/
NS_IMETHODIMP XPCOMWizard55::Hello()
{
#if defined(XP_WIN)
::MessageBoxW(NULL, L"Hello, XPCOM!", L"XPCOMWizard55", MB_OK|MB_ICONINFORMATION);
#endif
return NS_OK;
//return NS_ERROR_NOT_IMPLEMENTED;
}
/* void Sum (in long nFirst, in long nSecond, out long nResult); */
NS_IMETHODIMP XPCOMWizard55::Sum(int32_t nFirst, int32_t nSecond, IJSCallBack *jsCallBack, int32_t *nResult)
{
//js输出值
*nResult = nFirst + nSecond;
char szResult[256] = {0};
itoa(*nResult,szResult,10);
if (jsCallBack)
{
bool bRet = false;
//这里的第一个参数为0
jsCallBack->Call(0,szResult,&bRet);
}
return NS_OK;
}
这样就实现了简单的js回调。
9.编写测试main.js(上图标号2),JS代码如下:
var test =
{
call: function (index, data) {
alert("call back result");
alert(data);
}
}
function doXpCOM() {
try {
//建立XPCOM的实例"@gw.com.cn/xpcomwizard55;1"是唯一的类值和XPCOM中一致。
var aXPCOMWizard55 = Components.classes["@gw.com.cn/xpcomwizard55;1"]
.createInstance(Components.interfaces.IXPCOMWizard55);
aXPCOMWizard55.Hello();
//输出值必须为数据,不然输出不正确
var nResult = {};
//调用XPCOM的方法,test直接写上面定义好的脚本函数
aXPCOMWizard55.Sum(3, 5, test, nResult);
alert("Return result:");
alert(nResult.value);
} catch (e) {
alert(e);
}
}
10.设置调试的应用程序。如下图:
11.编译,成功OK。
12.直接运行。结果如下图
OK成功!!