分享
 
 
 

XPCOM--LINUX下的组件开发技术的一些补充与说明

王朝system·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

XPCOM--LINUX下的组件开发技术的一些补充与说明

原文出自:《世界商业评论》ICXO.COM ( 日期:2004-07-14 13:56)

--------------------------------------------------------------------------------

boise bjgxjob@163.com

--------------------------------------------------------------------------------

COM技术作为微软推行的一种组件技术,在WINDOWS平台站有重要地位,在模块重用,跨语言通信等方面都能见到其身影。但今天给我要介绍的是LINUX下的COM实现----XPCOM,这是MOZILLA浏览器项目中所使用的基本技术,我们可以用C++制作XPCOM组件,在C++客户程序或MOZILLA浏览器中通过JAVASCRIPT脚本来调用组件,从而实现软件模块的复用。

1、 配置XPCOM的开发环境。

首先到MOZILLA的FTP下载Gecko-sdk包,这是XPCOM的开发包,MOZILLA的源码中也包括该SDK。解压该tgz包,可以看到生成大约十多个目录:

/sdk/gecko-sdk/

/sdk/gecko-sdk/xpcom/bin

/sdk/gecko-sdk/xpcom/idl

/sdk/gecko-sdk/xpcom/include

/sdk/gecko-sdk/nspr

这里说明一下其中的一些基本部分。

/sdk/gecko-sdk/xpcom/bin下主要包含了一些文件:

xpidl:这是idl编译器,用以根据idl产生c++头文件或组件类型库文件.

Regxpcom:这是组件注册工作,如果我们在MOZILLA浏览器中调用组件,其实不会用该工具。

Xpt-dump:类型库查看程序,用来查看.xpt文件中的组件信息。

libxpcomglue.a:这是XPCOM的基本库文件,在生成组件时将会被连接到我们的组件库中。

/sdk/gecko-sdk/xpcom/idl,该目录中包含了idl数据类型定义文件。

/sdk/gecko-sdk/xpcom/include,其中包含了制作XPCOM时所需要的基本的C++头文件。

/sdk/gecko-sdk中还包含了其它一引起目录,如/sdk/sdk/gecko-sdk/string/include,其中包含了XPCOM中常字符串类的C++头

文件,如果我们的组件中需要使用这些类,只需包含进必要的头文件及库文件即可。

2、 撰写idl文件。

这里要先用到一个uuidgen(LINUX下类似MS GUIDGEN的一个命令行程序)用以产生组件的uuid, 我们将其输出先重定向到一个文本中,呆会儿即可使用,这里我们举一个简单的例子,来演示组件的生成过程。

Idl文件如下:

//filename: nsIMyCom.idl

//begin idl --------------------------------------

#include nsISupports.idl

[scriptable, uuid(5217115e-11fe-4d01-966d-9b27ffda6498)]

interface nsIMyCom:nsISupports//在这里需要注意的是:nsIMyCom以"nsI"为前缀,

//可以方便在之后的C++文件中生成相应的类名,类名为nsI之后的部份,如MyCom;

//若接口名前三个字母为其它的字符,一般生成的C++类的类名为_MYCLASS_

{

void Hello(in string in_str, [retval] out string out_str);

};

//end idl-----------------------------------------

好了,该组件很简单,只有一个接口,并且也只有一个方法,该方法有一个字符串输入参数in_str,并且有一个字符串返回值out_str。

3、编译该idl文件,并完成该组件对应的C++实现。

/sdk/gecko-sdk/xpcom/bin/xpidl -I/sdk/gecko-sdk/xpcom/bin/idl -m header nsIMyCom.idl

如果没有错误,这时在当前目录下将会生成一个nsIMyCom.h文件,该文件是idl编译器对应上面的idl文件所生成的c++头文件。

下面是编译器生成的nsIMyCom.h文件内容:

//--------------------------------------------------------

#ifndef __gen_nsIMyCom_h__

#define __gen_nsIMyCom_h__

#ifndef __gen_nsISupports_h__

#include nsISupports.h

#endif

/* For IDL files that dont want to include root IDL files. */

#ifndef NS_NO_VTABLE

#define NS_NO_VTABLE

#endif

/* starting interface: nsIMyCom */

#define NS_IMYCOM_IID_STR 5217115e-22fe-4d01-966d-9b27ffda6498

#define NS_IMYCOM_IID /

{0x5217115e, 0x22fe, 0x4d01, { 0x96, 0x6d, 0x9b, 0x27, 0xff, 0xda, 0x64, 0x98 }}

class NS_NO_VTABLE nsIMyCom : public nsISupports {

public:

NS_DEFINE_STATIC_IID_ACCESSOR(NS_IMYCOM_IID)

/* void Hello (in string in_str, [retval] out string out_str); */

NS_IMETHOD Hello(const char *in_str, char **out_str) = 0;

};

/* Use this macro when declaring classes that implement this interface. */

#define NS_DECL_NSIMYCOM /

NS_IMETHOD Hello(const char *in_str, char **out_str);

/* Use this macro to declare functions that forward the behavior of this interface to another object. */

#define NS_FORWARD_NSIMYCOM(_to) /

NS_IMETHOD Hello(const char *in_str, char **out_str) { return _to Hello(in_str, out_str); }

/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe

way. */

#define NS_FORWARD_SAFE_NSIMYCOM(_to) /

NS_IMETHOD Hello(const char *in_str, char **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->Hello

(in_str, out_str); }

#if 0

/* Use the code below as a template for the implementation class for this interface. */

/* Header file */

class nsMyCom : public nsIMyCom

{

public:

NS_DECL_ISUPPORTS

NS_DECL_NSIMYCOM

nsMyCom();

virtual ~nsMyCom();

/* additional members */

};

/* Implementation file */

NS_IMPL_ISUPPORTS1(nsMyCom, nsIMyCom)

nsMyCom::nsMyCom()

{

/* member initializers and constructor code */

}

nsMyCom::~nsMyCom()

{

/* destructor code */

}

/* void Hello (in string in_str, [retval] out string out_str); */

NS_IMETHODIMP nsMyCom::Hello(const char *in_str, char **out_str)

{

return NS_ERROR_NOT_IMPLEMENTED;

}

/* End of implementation class template. */

#endif

#endif /* __gen_nsIMyCom_h__ */

//---------------------------------------------------------

从上面可以看到, xpidl生成了对应该接口的头文件,同时还包括对该头文件实现的C++类模板.下一步的工作一样很轻松,

我们将#if 0 至#endif 之间的代码分别复制到新建的nsMyCom.h 和nsMyCom.cpp文件中,

注意其中有新增的代码,下面是生成的两个文件.

//filename: nsMyCom.h

#include nsImyCom.h

#define NS_MYCOM_CID /

{0x5217115e, 0x22fe, 0x4d01, { 0x96, 0x6d, 0x9b, 0x27, 0xff, 0xda, 0x64, 0x98 }}

//类似WINDOWS 中CLSID

#define NS_MYCOM_CONTRACTID @westsoft.org/mycom;1 //类似WINDOWS中的progid;

class nsMyCom : public nsIMyCom

{

public:

NS_DECL_ISUPPORTS

NS_DECL_NSIMYCOM

nsMyCom();

virtual ~nsMyCom();

/* additional members */

};

//filename: nsMyCom.cpp

#include nsMyCom.h

#include nsMemory.h

#include <cstdio>

#include <cstdlib>

#include <string>

NS_IMPL_ISUPPORTS1_CI(nsMyCom, nsIMyCom) //此处的宏已修改:注意这里与自动生成的C++代码的不同之处:NS_IMPL_ISUPPORTS1

nsMyCom::nsMyCom()

{

}

nsMyCom::~nsMyCom()

{

}

/* void Hello (in string in_str, [retval] out string out_str); */

NS_IMETHODIMP nsMyCom::Hello(const char *in_str, char **out_str)

{

printf(n-----------------n);

printf(%sn, in_str);

std::string str_tmp = your input is: ;

str_tmp += in_str;

*out_str = (char*)malloc(str_tmp.length() + 1);

*out_str = (char*)str_tmp.c_str();

return NS_OK;

}

4、完成组件的工厂方法及注册模块。

组件本身的实现就上面两个类即可以了. 但是我们仅把上面的类生成动态库是不能作为组件工作的,我们还需要做一件事情.实现组件的注册及创建相关的功能.这几乎是一个固定的模式.

下面是该部分的代码,跟MS中的实现类似,用了许多的宏:

#include nsIGenericFactory.h

#include nsMyCom.h

NS_GENERIC_FACTORY_CONSTRUCTOR(nsMyCom)

static NS_METHOD nsMyComRegistrationProc(nsIComponentManager *aCompMgr,

nsIFile *aPath, const char *registryLocation, const char *componentType, const nsModuleComponentInfo *info)

{

return NS_OK;

}

static NS_METHOD nsMyComUnregistrationProc(nsIComponentManager *aCompMgr,

nsIFile *aPath, const char *registryLocation, const nsModuleComponentInfo *info)

{

return NS_OK;

}

NS_DECL_CLASSINFO(nsMyCom)

static const nsModuleComponentInfo components[] ={

{ "nsMyCom Component", NS_MYCOM_CID, NS_MYCOM_CONTRACTID,nsMyComConstructor,//这里,"Constructor"是固定的,nsMyCom是类名

nsMyComRegistrationProc /* NULL if you dont need one */,

nsMyComUnregistrationProc /* NULL if you dont need one */,

NULL /* no factory destructor */,

NS_CI_INTERFACE_GETTER_NAME(nsMyCom),

NULL /* no language helper */,

&NS_CLASSINFO_NAME(nsMyCom)

}

};

NS_IMPL_NSGETMODULE(nsMyComModule, components)//nsMyComModule是模块源码文件编译后的模块名:nsMyComModule

5、制作Makefile,生成,安装组件

好了,我们可以编写Makefile文件,来编译我们刚才编写的组件了.

#filename:Makefile

#begine-------------------------------------

CPP = g++

CPPFLAGS += -fno-rtti -fno-exceptions -shared

GECKO_SDK_PATH = /sdk/gecko-sdk

XPIDL = $(GECKO_SDK_PATH)/xpcom/bin/xpidl

#生成C++头文件

CPPHEADER = -m header

#生成类型库文件

TYPELIB = -m typelib

REGDIR = /usr/local/lib/mozilla-1.6

OUTDIR = $(REGDIR)/components

GECKO_CONFIG_INCLUDE = -include mozilla-config.h

GECKO_DEFINES = -DXPCOM_GLUE

GECKO_INCLUDES = -I$(GECKO_SDK_PATH)

-I$(GECKO_SDK_PATH)/xpcom/include

-I$(GECKO_SDK_PATH)/nspr/include

GECKO_LDFLAGS = -L$(GECKO_SDK_PATH)/xpcom/bin -lxpcomglue

-L$(GECKO_SDK_PATH)/nspr/bin -lnspr4

GECKO_IDL = -I$(GECKO_SDK_PATH)/xpcom/idl

build: idl nsMyCom.o nsMyComModule.o

$(CPP) $(CPPFLAGS) -o libxpmycom.so $(GECKO_DEFINES)

$(GECKO_LDFLAGS) nsMyCom.o nsMyComModule.o

chmod +x libxpmycom.so

idl: nsIMyCom.idl

$(XPIDL) $(GECKO_IDL) $(CPPHEADER) nsIMyCom.idl

$(XPIDL) $(GECKO_IDL) $(TYPELIB) nsIMyCom.idl

nsMyCom.o: nsMyCom.cpp

$(CPP) $(GECKO_CONFIG_INCLUDE) $(GECKO_DEFINES)

$(GECKO_INCLUDES) -c nsMyCom.cpp -o nsMyCom.o

nsMyComModule.o: nsMyComModule.cpp

$(CPP) $(GECKO_CONFIG_INCLUDE) $(GECKO_DEFINES)

$(GECKO_INCLUDES) -c nsMyComModule.cpp -o nsMyComModule.o

install:

cp nsIMyCom.xpt $(OUTDIR)/

cp libxpmycom.so $(OUTDIR)/

clean:

rm *.o

rm *.so

rm *.*~

rm *~

#end-------------

如果一切无误,我们make之后,g++就会在当前目录下生成libxpmycom.so库文件,nsIMyCom.xpt是相应的类型文件。然后再将该组件安装到mozilla的组件目录中:

make install

该组件库及对应的类型库nsIMyCom.xpt将会被拷到/usr/local/lib/mozilla-1.6/components(要确认你的组件目录,如mozilla1.4目录一般为usr/local/lib/mozilla-1.4/components)目录中。

这时我们可以从控制台启动mozilla浏览器,在浏览器输出的一系列信息中,将会有该组件被注册成功的信息。

6、在html/javascript中测试该组件。

该html如下:

//------------------------------------

<html>

<head>

<title>

测试XPCOM组件

</title>

</head>

<body>

<script>

netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

var mycom = Components.classes[@westsoft.org/mycom;1].createInstance();

mycom = mycom.QueryInterface(Components.interfaces.nsIMyCom);

function testxpcom(f)

{

netscape.security.PrivilegeManager.enablePrivilege(UniversalXPConnect);

var ret_string;

ret_string = mycom.Hello(document.form_test.input_string.value);

alert(ret_string);

}

</script>

<form name=form_test>

输入信息:

<textarea name = input_string cols = 70 rows = 5></textarea>

<input type=button value=testxpcom onClick = testxpcom(this.form);>

</form>

</body>

</html>

//--------------------------------------------------

我们在mozilla中打开该html,在输入框中输入一些文字,在点击testxpcom后,怎么样,看到从组件返回的信息了吗?

另外,上面的输入信息如果是中文,则返回中会产生乱码,xpcom idl中有nsAString, wstring等支持unicode的字符串类型,可以利用这些类型来解决汉字编码的问题,以下是我使用的方法。

假设XPCOM内部已经正常地取得了GB2312的汉字编码的数据,要在测试页面上由JavaScript来正常地解释与显示这些编码,就必须要把GB2312转换成为UNICODE编码。在此之前,需要修改前面所定义的IDL文件:nsIMyCom.idl,例如,修改如下:

//filename: nsIMyCom.idl

//begin idl --------------------------------------

#include nsISupports.idl

[scriptable, uuid(5217115e-11fe-4d01-966d-9b27ffda6498)]

interface nsIMyCom:nsISupports

{

void Hello(in string in_str, [retval] out wstring out_str);

};

//end idl-----------------------------------------

生成相应的HEADER文件后,修改C++类文件并编译,安装后运行就可以在Mozilla中正常显示出汉字了。

GB2312转换为UNICODE的代码如下:

//begin-------------------------

#include <iconv.h>

#define MAX_PATH 400

char * GetUnicode(char * ucInGB2312, char *ucOutUnicode)

{

if(ucInGB2312 == NULL || ucOutUnicode == NULL)

{

return "\0";

}

char *strIn = ucInGB2312;

char *strRet = ucOutUnicode;

char tmp[MAX_PATH*10] = {0};

char *pTmp = tmp;

size_t nInLen = strlen(ucInGB2312);

size_t nOutLenLeft = nInLen * 3;

size_t nOrgLen = nInLen*3;

iconv_t cd = 0;

if((cd = iconv_open("UNICODE", "GB2312")) == (iconv_t)-1)

{

return "\0";

}

if(iconv(cd, &strIn, &nInLen, &pTmp, &nOutLenLeft) == (size_t)-1)

{

return "\0";

}

memcpy(ucOutUnicode, tmp, (nOrgLen - nOutLenLeft));

iconv_close(cd);

return strRet;

}

//end--------------------------

以上只是展示了XPCOM组件的基本技术,还有许多内容未提及,如果要将该技术应用于项目中,更多的资料请查阅mozilla的网上资源。

以上是根据《XPCOM--LINUX下的组件开发技术》做了补充说明,希望对这方面的开发者有帮助,不到之处请多多指教!

若有问题与我联系:bjgxjob@163.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有