在重新翻阅 << Creating Applications with Mozilla >> 以及 Alex SirotaLonecat 的帖子后, 总算对 XPCOM 有点入门了… 记录个简单的 C++ component 的例子, 作为以后的参考.

需要的软件: gecko-sdk

1. 建立一个 idl 文件(接口定义)

1
2
3
4
5
6
7
#include "nsISupports.idl"
 
[scriptable, uuid(a765a62c-eb6a-4e4f-a1a8-c66340d3e892)]
interface IMyComponent : nsISupports
{
  long Add(in long a, in long b);
};

其中的 uuid 可由 uuidgen 生成.

2. 使用 xpidl 生成相应的头文件和类型库文件

1
2
xpidl -m header -I_DIR_ IMyComponent.idl
xpidl -m typelib -I_DIR_ IMyComponent.idl

“_DIR_” 替换为gecko-sdk/idl的路径

3. 建立自己组件的头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef _MY_COMPONENT_H_
#define _MY_COMPONENT_H_
 
#include "IMyComponent.h"
 
#define MY_COMPONENT_CONTRACTID "@mozilla.org/MyComponent;1"
#define MY_COMPONENT_CLASSNAME "A Simple XPCOM Sample"
#define MY_COMPONENT_CID  { 0xa765a62c, 0xeb6a, 0x4e4f, { 0xa1, 0xa8, 0xc6, 0x63, 0x40, 0xd3, 0xe8, 0x92 } }
 
/* Header file */
class MyComponent : public IMyComponent
{
public:
  NS_DECL_ISUPPORTS
  NS_DECL_IMYCOMPONENT
 
  MyComponent();
  virtual ~MyComponent();
  /* additional members */
};
 
 
#endif //_MY_COMPONENT_H_

其中 /* Header file */ 下那段类的定义是从 xpidl 生成的 IMyComponent.h 文件里 copy 过来的, 然后把其中的 “_MYCLASS_” 改成自己的组件名.

4. 创建组件的实现文件(也就是cpp啦~)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "MyComponent.h"
 
NS_IMPL_ISUPPORTS1(MyComponent, IMyComponent)
 
MyComponent::MyComponent()
{
  /* member initializers and constructor code */
}
 
MyComponent::~MyComponent()
{
  /* destructor code */
}
 
/* long Add (in long a, in long b); */
NS_IMETHODIMP MyComponent::Add(PRInt32 a, PRInt32 b, PRInt32 *_retval)
{
	*_retval = a + b;
	return NS_OK;
}

其中的内容同样是来自 xpidl 生成的 IMyComponent.h , 拷贝其中的 /* Implementation file */ 段, 同样将 “_MYCLASS_” 改成自己的组件名.

5. 创建自己的模块定义文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "nsIGenericFactory.h"
#include "MyComponent.h"
 
NS_GENERIC_FACTORY_CONSTRUCTOR(MyComponent)
 
static nsModuleComponentInfo components[] =
{
    {
       MY_COMPONENT_CLASSNAME, 
       MY_COMPONENT_CID,
       MY_COMPONENT_CONTRACTID,
       MyComponentConstructor,
    }
};
 
NS_IMPL_NSGETMODULE("MyComponentsModule", components)

6. 最后则是需要建立一个 Makefile 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
CXX   = c++
 
CPPFLAGS +=     -fno-rtti              \
 
		-fno-exceptions        \
 
		-shared  
 
 
 
# Change this to point at your Gecko SDK directory. 
 
GECKO_SDK_PATH = /home/duo/gecko-sdk
 
 
 
# GCC only define which allows us to not have to #include mozilla-config 
 
# in every .cpp file.  If your not using GCC remove this line and add 
 
# #include "mozilla-config.h" to each of your .cpp files. 
 
GECKO_CONFIG_INCLUDE = -include mozilla-config.h 
 
 
 
GECKO_DEFINES  = -DXPCOM_GLUE
 
 
 
GECKO_INCLUDES = -I $(GECKO_SDK_PATH)/include 
 
 
 
GECKO_LDFLAGS =  -L $(GECKO_SDK_PATH)/lib -lxpcomglue \
 
                 -lnspr4      \
 
                 -lplds4      
 
 
 
FILES = MyComponent.cpp MyComponentModule.cpp 
 
 
 
TARGET = MyComponent.so
 
 
 
build: 
 
	$(CXX) -Wall -Os -o $(TARGET) $(GECKO_CONFIG_INCLUDE) $(GECKO_DEFINES) $(GECKO_INCLUDES) $(GECKO_LDFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(FILES)
 
	chmod +x $(TARGET)
 
	strip $(TARGET)
 
 
 
clean: 
 
	rm $(TARGET)

7. 执行下 make , 就能得到我们想要的 MyComponent.so 了.

8. JavaScript 调用

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
	try {
		var obj = Components.classes["@mozilla.org/MyComponent;1"].createInstance();
		obj = obj.QueryInterface(Components.interfaces.IMyComponent);
	} catch (err) {
		alert(err);
		return;
	}
	var res = obj.Add(3, 4);
	alert('Performing 3+4. Returned ' + res + '.');

9. 如果需要在 XULRunner 下使用, 那么将 MyComponent.so 和 IMyComponent.xpt 拷贝到您的应用程序的
components 目录, 同时别忘了将配置文件 ~/.companyname/appname/ 删除.

Related posts:

  1. 关于 Mozilla 的 Plugin 编译
  2. A mozilla gtk plugin sample
  3. CHMReader compile issues on Mac
  4. aghttpd: a small C library for creating a HTTP server (based on GLib)

Tags: , ,



Leave a Comment