A Simple XPCOM Tutorial

Click here to Skip to main content

Step by step XPCOM Creation and implementation in C++
 

Purpose of this Article

I have written this tutorial for programmers who are just starting out in XPCOM. The article briefly covers the writing your own XPCOM objects and how to reuse existing XPCOM components using VC8.0.This article does not cover XPCOM Basics or concepts.

Project Settings or Development Setup was a big problem for me. Also Registering XPCOM is an another troublesome issue. Because xpti.dat and compreg.dat must be deleted from profile directory

Introduction

XPCOM is a cross platform component object model, similar to Microsoft COM. It has multiple language bindings, letting the XPCOM components be used and implemented in JavaScript, Java, and Python in addition to C++. Interfaces in XPCOM are defined in a dialect of IDL called XPIDL.

For me, understanding XPCOM has been no less than an odyssey. I believe that every programmer who wishes to understand the basic principles behind XPCOM, must write at least one simple XPCOM object using plain C++. In this article I present the guidelines for creating simple XPCOM objects from first principles. The components should be usable by both VC++/ JavaScript clients.

As an exercise we will attempt to design a XPCOM component that will implement a hypothetical super-fast addition algorithm. The component must take in two parameters of long data type, and return to the user another long parameter that will be an outcome of our addition algorithm. 

How to write C++ XPCOM components

Step 1: Development Setup

  • Use the right xulrunner SDK for your XULRunner release, I use xulrunner-1.9.2
  • Use a Microsoft compiler, I use Visual C++2005

Here is what my folder structure looks like:

       XPCOM
            - xulrunner-sdk
                bin
                lib
                idl
                include
               
            - sample_xpcom  (xpcom creation)
                Debug
                Release

Step 2: Create a VC++ Project

  • Start an empty Win32 project in Visual Studio, selecting the "Dynamic Linked Library (DLL)" option.
  • Create and IDL file describing the interface of your component
  • Run xpidl twice on the IDL file, with
  • "xpidl -I < xulrunner-sdk/idl path> -m header <youridl>" and
  • "xpidl -I < xulrunner-sdk/idl path> -m typelib < youridl>".
  • Make the following tweaks:
  • Add “../xulrunner-sdk/include” to Additional Include Directories
  • Add“../xulrunner-sdk/lib” to Additional Library Directories
  • Add“nspr4.lib xpcom.lib xpcomglue_s.lib” to Additional Dependencies
  • Add “XP_WIN;XP_WIN32″ to Preprocessor Definitions
  • Turnoff precompiled headers (just to keep it simple)
  • Use a custom build step for the XPCOM IDL file (exclude from build by MIDL)

Step 3: Create an XPCOM Component

XPCOM component is made up of 3 parts:

  • Component interface described using IDL. The interface defines the methods, including arguments and return types, of the component.
  • Component implementation using C++. The implementation is where the methods actually do the work.
  • Component factory module, also in C++. The factory is in charge of creating instances of the implementations.
  • Build your component.

Step 4: Register XPCOM Component

  • Copy your XPT and DLL files to the Firefox components directory.
  • Normally, if this was installed as part of an extension, it would automatically search this directory and find these files. But now we have to force a refresh. Delete xpti.dat. and compreg.dat from your profile directory
  • Firefox will regenerate them on next restart or we can use regxpcom.exe like this
  • “regxpcom -x < xulrunner-sdk >/bin /components/<yourxpcom>.dll"
  • But I found some problems by this command. So , I used this way -
  • “regxpcom -x < FireFoxDir >/bin /components/<yourxpcom>.dll"
Now Start the Example

Let’s specify a simple interface:

           
    #include "nsISupports.idl"
                          
    [scriptable, uuid(658ABC9E-29CC-43E9-8A97-9D3C0B67AE8B)]
    interface ISample : nsISupports
    {
      long    Add(in long a, in long b);
    };

Remember to generate your own GUID.

The next step is to compile the IDL into a type-library (*.XPT) and a C++ header file (*.H), which we can use to define our implementation object. We have touse XPIDL.EXE twice, like this:

  • {path_to_ xulrunner-sdk }/bin/xpidl.exe -m header -I../ xulrunner-sdk /idl {your_idl_file}
  • {path_to_ xulrunner-sdk }/bin/xpidl.exe -m typelib -I../ xulrunner-sdk /idl {your_idl_file}

The generated H file actually has a skeleton implementation (commented out).

You can take the code and create implementation H and CPP files. They could look like this:

Header file:

            
    #ifndef _SAMPLE_H_
    #define _SAMPLE_H_
                          
    #include "ISample.h"
                          
    #define SAMPLE_COMPONENT_CONTRACTID "@cn.ibm.com/XPCOM/sample;1"
    #define SAMPLE_COMPONENT_CLASSNAME "Sample XPCOM Interface Layer"
    #define SAMPLE_COMPONENT_CID  {0x658abc9e, 0x29cc, 0x43e9,{ 0x8a, 0x97, 0x9d, 0x3c, 0x0b, 0x67, 0xae, 0x8b } }
                          
    //658abc9e-29cc-43e9-8a97-9d3c0b67ae8b
    class CSample : public ISample
    {
    public:
          NS_DECL_ISUPPORTS
          NS_DECL_ISAMPLE
          
          CSample();
          virtual ~CSample();
                          
          //additional member functions
          int Add();
    };
    #endif

CPP file:

                    
    #include "Sample.h"
                          
    NS_IMPL_ISUPPORTS1(CSample, ISample)
                          
    CSample::CSample()
    {
          /* constructor code */
    }     
                          
    CSample::~CSample()
    {
          /* destructor code */
    }
                          
                          
                          
                          
    /* long Add (in long a, in long b); */
    NS_IMETHODIMP CSample::Add(PRInt32 a, PRInt32 b, PRInt32 *_retval)
    {
          *_retval = a + b;
          return NS_OK;
    }

Lastly, we need to create the module implementation.

         
    #include "nsIGenericFactory.h"
    #include "Sample.h"
      
                      
    NS_GENERIC_FACTORY_CONSTRUCTOR(CSample)
                          
    static nsModuleComponentInfo components[] =
    {
          {
                      SAMPLE_COMPONENT_CLASSNAME,
                      SAMPLE_COMPONENT_CID,
                      SAMPLE_COMPONENT_CONTRACTID,
                      CSampleConstructor,
          }
    };
                          
    NS_IMPL_NSGETMODULE("sample_module", components)

How to use XPCOM components from C++ code

Step 1: Development Setup

  • Use the right xulrunner SDK for your XULRunner release, I use xulrunner-1.9.2
  • Use a Microsoft compiler, I use Visual C++2005

Here is what my folder structure looks like:

       XPCOM
            - xulrunner-sdk
                bin
                lib
                idl
                include
                   
            - XULTesting (xpcom implementaion)
                Debug
                Release

Step 2: Create a VC++ Project

  • Start an empty Win32 project in Visual Studio, selecting the "Console Application" option.
  • Create a cpp file that includes the header file.
  • Make the following tweaks:
  • Add “../xulrunner-sdk/include” to Additional Include Directories
  • Add“../xulrunner-sdk/lib, ../xulrunner-sdk/sdk/bin” to Additional Library Directories
  • Change the Output directory to < FireFoxDir >
  • Add“nspr4.lib xpcom.lib xpcomglue_s.lib” to Additional Dependencies
  • Add “XP_WIN;XP_WIN32″ to Preprocessor Definitions
  • Turnoff precompiled headers (just to keep it simple)
  • Now Build the Application

Here is the CPP file.

            
    #include "stdafx.h"
    #include "nsCOMPtr.h"
    #include "nsServiceManagerUtils.h"
               
    #include "../sample_xpcom/ISample.h"
    #include "../sample_xpcom/Sample.h"
               
               
    int _tmain(int argc, _TCHAR* argv[])
    {
          nsresult rv;
                          
          nsCOMPtr<nsiservicemanager> servMan;
        
          // You Can Get the service manager several ways

	  // Get Service manager : WAY 1
	  //---------------------------------------

          rv = NS_GetServiceManager(getter_AddRefs(servMan));
          if (NS_FAILED(rv))
          {
                printf("ERROR: XPCOM error [%x]./n", rv);
                return -1;
          }
          //-----------End of Getting Way 1 -----------------


	  // Get Service manager : WAY 2
	  //--------------------------------------------------
          /*                
          // Initialize XPCOM and check for failure ...
          rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); 
          if ( NS_FAILED(rv) )
          {
                printf("Calling NS_InitXPCOM returns [%x]./n", rv);
                return -1;
          }*/
          //-----------End of Getting Way 2 --------------------
                
          // Get the Component object;
          nsCOMPtr<isample> iSample;
          rv = servMan->GetServiceByContractID(SAMPLE_COMPONENT_CONTRACTID, 
                             NS_GET_IID(ISample),getter_AddRefs(iSample));
                   
          if ( NS_FAILED(rv) )
          {
                printf("Calling GetServiceByContractID returns [%x]./n", rv);
                NS_ShutdownXPCOM(nsnull);
                return -1;
          }
                   
          int nFirstVal, nSecondVal, nResult;
          nFirstVal= 5; 
          nSecondVal = 10;
          iSample->Add(nFirstVal, nSecondVal, &nResult);
                   
         _tprintf(_T("/nThe Result is : %d/n"), nResult);
                              
         // Shutdown XPCOM

         // Here also several ways you can follow

	 // Explicitly Releasing ISample
	 //NS_RELEASE(iSample); 

         // Or Shutdown Service manager 
	 // The nsIServiceManager instance that was returned by NS_InitXPCOM2 or nsnull.
         NS_ShutdownXPCOM(nsnull);

         return 0;
    }

References

For further details of XPCOM, best reference can be,

Note: An easy and simple way of learning this is to just use the projects and debug with break point. If there are any suggestions, requests or problems please inform me.

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值