As a component technology implemented by Microsoft, COM technology has an important role in the Windows platform station, which can be seen in module reuse, cross-language communications, etc. But today I want to introduce the COM implementation under Linux ---- XPCOM, this is the basic technology used in the Mozilla browser project, we can use C to make XPCOM components, passed in the C client or Mozilla browser The JavaScript script calls the component to implement the software module multiplexing.
1. Configure the development environment of XPCOM.
First go to Mozilla's FTP to download the Gecko-SDK package, which is the development kit of XPCOM, and the SDK is also included in the source code of Mozilla. Unzip the TGZ package, you can see how much more than a dozen directory:
/ SDK / GECKO-SDK /
/ SDK / GECKO-SDK / XPCOM / BIN
/ SDK / GECKO-SDK / XPCOM / IDL
/ SDK / GECKO-SDK / XPCOM / INCLUDE
/ SDK / GECKO-SDK / NSPR
......
Here, some of the basic parts thereof will be described.
/ SDK / GECKO-SDK / XPCOM / BIN mainly includes some files:
XPIDL: This is an IDL compiler to generate a C header file or component type library file according to IDL.
RegXPCOM: This is a component registration, if we call components in the Mozilla browser, it does not use the tool.
XPT-DUMP: Type Library View Programs, used to view component information in the .xpt file.
LIBXPCOMGLUE.A: This is the basic library file of XPCOM, which will be connected to our component library when generating components.
/ SDK / GECKO-SDK / XPCOM / IDL contains the IDL data type definition file.
/ SDK / Gecko-SDK / XPCOM / include, which contains the basic C header file required to make XPCOM.
/ SDK / GECKO-SDK also includes other one from the directory, such as / SDK / SDK / Gecko-SDK / String / Include, which contains XPCOM constant string C headers
File, if you need to use these classes in our components, you only need to include the necessary header files and library files.
2. Write the IDL file.
Here, you must first use a uuidgen (a command line program similar to MS Guidgen under Linux) to generate the UUID of the component, we will redirect it to a text first, then you can use it, here we will give a simple Examples to demonstrate the generation process of components.
The IDL file is as follows:
// 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 string out_str);
}
// end IDL ---------------------------------------
Ok, the component is very simple, only one interface, and there is only one method, which has a string input parameter in_str, and has a string return value OUT_STR.
3. Compile this IDL file and complete the C implementation corresponding to the component.
/ sdk / gecko-sdk / xpcom / bin / xpidl -i / sdk / gecko-sdk / xpcom / bin / idl -m header nsimycom.IDL If there is no error, then a nsimycom.h file will be generated in the current directory. This file is a C header file generated by the IDL compiler corresponding to the IDL file above.
Here is the content of the NSIMYCOM.H file generated by the compiler:
/ / -------------------------------------------------------------------------------------------- ------------
#ifndef __gen_nsimycom_h__
#define __ge_nsimycom_h__
#ifndef __gen_nsisupports_h__
#include "nsisupports.h"
#ENDIF
/ * For idl files this don't 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 this 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 importation class for this interface. * // * Header file * /
Class nsmycom: public nsimycom
{
PUBLIC:
NS_DECL_ISUPPPPPPports
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 importation class template. * /
#ENDIF
#ENDIF / * __GEN_NSIMYCOM_H__ * /
/ / -------------------------------------------------------------------------------------------- ---------
As can be seen from the above, XPIDL generates a header file that should interface, but also includes a C class template implemented on the header file. It is very easy as the next step.
We copied the code between #IF 0 to #ENDIF to the new NSMYCOM.H and NSMYCOM.CPP files, respectively.
Note that there is new code, the following is the generated two files.
// filename: nsmycom.h
#include "nsimycom.h"
#define ns_mycom_cid /
{0x5217115e, 0x22FE, 0x4D01, {0x96, 0x6d, 0x9b, 0x27, 0xff, 0xda, 0x64, 0x98}}
// Similar to CLSID in Windows
#define ns_mycom_contractid "@ westsoft.org / mycom; 1" // Similar to PROGID in WINDOW;
Class nsmycom: public nsimycom
{
PUBLIC:
NS_DECL_ISUPPPPPPports
NS_DECL_NSIMYCOM
NSMYCOM ();
Virtual ~ nsmycom ();
/ * Additional members * /
}
// filename: nsmycom.cpp
#include "nsmycom.h"
#include "nsmemory.h"
#include
#include
#include
NS_IMPL_ISUPPORTS1_CI (NSMYCOM, NSIMYCOM) // The macro here has been modified.
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 ("% s / n", in_str);
Std :: str - 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. Complete the factory method and registration module of the component.
The implementation of the component itself can be above two classes. But we only have the above class to generate a dynamic library. We need to do one thing. We also need to do something. Implement the registration of the component and create a related function. This is almost It is a fixed mode.
Below is the code of this section, similar to the implementation in MS, with many macros:
#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 nsmodulects [] = {
{"nsmycom component", ns_mycom_cid, ns_mycom_contractid, nsmycomconstructor,
NSMYCOMREGISTRATIONPROC / * NULL IF you dont need * /,
NSMYCOMUNREGISTRATIONPROC / * NULL IF you dont need one * /,
Null / * no factory designructor * /,
NS_CI_Interface_getter_name (nsmycom),
Null / * no language helper * /,
& Ns_classinfo_name (nsmycom)
}
}
NS_IMPL_NSGETMODULE (NSMYCOMMODULE, COMPONENTS)
5, make Makefile, build, install components
Ok, we can write the Makefile file to compile the components we have just prepared.
#filename: makefile
#Begine -------------------------------------
CPP = G
CPPFLAGS = -fno-rtti -fno-exceptions -shared
Gecko_sdk_path = / sdk / gecko-sdk
XPIDL = $ (gecko_sdk_path) / XPCOM / BIN / XPIDL
Cppheader = -m header
TYPELIB = -M Typelib
Regdir = /usr/local/lib/mozilla-1.6outdir = $ (regdir) / Components
Gecko_config_include = -include mozilla-config.h
Gecko_defines = -dxpcom_glue
Gecko_includes = -i $ (gecko_sdk_path) /
-I $ (gecko_sdk_path) / xpcom / incrude /
-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 / id1
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) $ (CPPHEADER) NSIMYCOM.IDL
$ (XPIDL) $ (gecko_idl) $ (typeelib) 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 -------------
If everything is correct, we will generate the libxpmycom.so library file in the current directory after our make. Then install the component into the component directory of Mozilla:
Make Install
The component library and corresponding type library nsimycom.xpt will be copied to /usr/local/lib/mozilla-1.6/components (To confirm your component directory, such as Mozilla1.4 directory is usually USR / local / lib / mozilla -1.4 / Components directory.
At this time we can launch the Mozilla browser from the console, in a series of information of the browser output, will have information that the component is registered successfully.
6. Test the component in HTML / JavaScript.
The HTML is as follows:
// ------------------------------------
Test XPCOM components
title>
hEAD>
Netscape.security.privilegeManager.enablePrivilege ("UniversalXPConnect");
Var mycom = components.classes [@ westsoft.org/mycom; "; ";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>