首先,打开VS2010,新建一个Win32 Dynamic-Link Library空DLL项目,名称为XPCOMSample。
该工程将有四个文件:CSample.h, ISample.idl, CSample.cpp, CSampleModule.cpp。其中,CSample.h和CSample.cpp是对ISample.idl的具体实现,CSampleModule.cpp定义了一些模块信息,如XPConnect使用的合约ID。
首先新建名称为ISample.idl的文件:
#include "nsISupports.idl"
//uuid的内容(IID)可以使用GUID工具生成(guidgen.exe)
[scriptable, uuid(ED35BE65-DFA3-4674-B02D-161247F2CB0A)]
interface ISample : nsISupports
{
attribute string Value;
string Test(in string value);
};
接着创建实现类CSample。编辑CSample.h内容如下:
#include "ISample.h"
#define NS_SAMPLE_CID { 0x45879e7c, 0x4d10, 0x460a, { 0xbe, 0x28, 0x2a, 0x6f, 0xdb, 0xc0, 0xe3, 0x92 } }
#define NS_SAMPLE_CONTRACTID "@sapmple.net/sample;1"
class CSample : public ISample
{
public:
CSample();
//声明继承自nsISupports的三个成员QueryInterface, AddRef 和 Release
//有现成的宏可以使用,当然也可以自行书写
NS_DECL_ISUPPORTS
//声明继承自ISample的成员
//有现成的宏可以使用,当然也可以自行书写
//要注意的是,该宏由xpidl自动生成于ISample.h文件中;
//另外,在ISample.h文件中,xpidl也会自动生成和本文件内容类似的实现类模板
NS_DECL_ISAMPLE
private:
~CSample();
char* mValue;
};
#include "CSample.h"
#include "nsMemory.h"
#include "nsEmbedString.h"
#include "nsIClassInfoImpl.h"
CSample::CSample() : mValue(nsnull)
{
mValue = (char*)nsMemory::Clone("initial value", 14);
}
CSample::~CSample()
{
if (mValue) nsMemory::Free(mValue);
}
NS_IMPL_CLASSINFO(CSample, NULL, 0, NS_SAMPLE_CID)
NS_IMPL_ISUPPORTS1_CI(CSample, ISample)
NS_IMETHODIMP CSample::GetValue(char** aValue)
{
NS_PRECONDITION(aValue != nsnull, "null ptr");
if (! aValue) return NS_ERROR_NULL_POINTER;
if (mValue)
{
*aValue = (char*) nsMemory::Clone(mValue, strlen(mValue) + 1);
if (! *aValue) return NS_ERROR_NULL_POINTER;
}
else *aValue = nsnull;
return NS_OK;
}
NS_IMETHODIMP CSample::SetValue(const char* aValue)
{
NS_PRECONDITION(aValue != nsnull, "null ptr");
if (! aValue) return NS_ERROR_NULL_POINTER;
if (mValue) nsMemory::Free(mValue);
mValue = (char*) nsMemory::Clone(aValue, strlen(aValue) + 1);
return NS_OK;
}
NS_IMETHODIMP CSample::Test(const char *value, char **_retval NS_OUTPARAM)
{
NS_PRECONDITION(_retval != nsnull, "null ptr");
if (! _retval) return NS_ERROR_NULL_POINTER;
if (mValue)
{
*_retval = (char*) nsMemory::Clone(mValue, strlen(mValue) + 1);
if (! *_retval) return NS_ERROR_NULL_POINTER;
}
else *_retval = nsnull;
return NS_OK;
}
最后,添加CSampleModule.cpp:
#include "mozilla/ModuleUtils.h"
#include "nsIClassInfoImpl.h"
#include "CSample.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(CSample)
NS_DEFINE_NAMED_CID(NS_SAMPLE_CID);
static const mozilla::Module::CIDEntry kSampleCIDs[] = {
{ &kNS_SAMPLE_CID, false, NULL, CSampleConstructor },
{ NULL }
};
static const mozilla::Module::ContractIDEntry kSampleContracts[] = {
{ NS_SAMPLE_CONTRACTID, &kNS_SAMPLE_CID },
{ NULL }
};
static const mozilla::Module::CategoryEntry kSampleCategories[] = {
{ "my-category", "my-key", NS_SAMPLE_CONTRACTID },
{ NULL }
};
static const mozilla::Module kSampleModule = {
mozilla::Module::kVersion,
kSampleCIDs,
kSampleContracts,
kSampleCategories
};
NSMODULE_DEFN(CSampleModule) = &kSampleModule;
NS_IMPL_MOZILLA192_NSGETMODULE(&kSampleModule)
代码部分到此就结束了,下面开始着手编译。首先为预处理器添加:XP_WIN和MOZ_NO_MOZALLOC:
WChar_t视为内置类型设置为false:
关闭预编译头:
然后设置依赖项:xpcom.lib mozalloc.lib xpcomglue_s.lib nspr4.lib(替换原来默认的那些lib)
设置添加各搜索目录(我的Gecho2.0的路径为D:\xulrunner-sdk\SDK):
创建idl批处理文件(customBuild.bat):
D:/xulrunner-sdk/sdk/bin/xpidl.exe -I D:/xulrunner-sdk/sdk/idl -m header ISample.idl
D:/xulrunner-sdk/sdk/bin/xpidl.exe -I D:/xulrunner-sdk/sdk/idl -m typelib ISample.idl
使用自定义构造步骤,以取代MIDL对idl的编译(在解决方案的ISample.idl文件上右键,选择属性):
应用后左侧的MIDL将作出变更:
现在,就可以进行编译了。完成后,将获得ISample.h、ISample.xpt;在debug目录下还有:XPCOMSample.dll、XPCOMSample.lib
本人写的测试例子会报错:TypeError: Components.classes['@sapmple.net/sample;1'] is undefined
例子本身并没有错误,而是组件没有注册
如果有人知道放到FF Nightly11.0下,在js中进行测试的方法,请留言告知,谢谢
原来是权限的问题--
[15:23:26.061] netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
[15:33:42.091] Use of enablePrivilege is deprecated. Please use code that runs with the system principal (e.g. an extension) instead. @ file:///F:/tiewen/Mozilla/XPCOM/XPCOMSample/test.htm
二进制组件已不推荐使用,如果要用,需要封装到扩展中,真鸡巴恶心