Click here to Skip to main content
Click here to Skip to main content

A Simple XPCOM Tutorial

By , 30 Jun 2010
 

Purpose of this Article

I have written this tutorial for programmers who are just starting out in XPCOM. The article briefly covers 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 and Development Setup was a big problem for me. Also, registering XPCOM is another troublesome issue because xpti.dat and compreg.dat must be deleted from the profile directory.

Introduction

XPCOM is a cross platform component object model, similar to Microsoft COM. It has multiple language bindings, letting 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 an 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 an 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)
    • Add "/Zc:wchar_t-" in the additional option of C++ Command Line to support wchar_t
    • Use a custom build step for the XPCOM IDL file (exclude from build by MIDL)

Step 3: Create an XPCOM Component

An XPCOM component is made up of three 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 the 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 the "xpti.dat" and "compreg.dat" files from your profile directory. Add "<yourxpcom>.dll" at the end of the "components.list" file.
  • 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 with 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 to use 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 the 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
    • Add "/Zc:wchar_t-" in the additional option of C++ Command Line to support wchar_t
    • 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;
}

Next

My next article is about how to convert an MS COM component to an XPCOM component; i.e., step by step XPCOM creation from Microsoft COM.

References

For further details of XPCOM, the best reference is:

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.

History

  • 28/06/2010: Initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Md. Mazharul Islam Khan
Software Developer (Senior) Eyeball Networks Inc, Dhaka
Bangladesh Bangladesh
Member
I strongly believe, a person's strongest point is to know his/her weak point. I try to be simple.
 
I have completed BSc in Computer Science & Engineering from Shah Jalal University of Science & Technology, Sylhet, Bangladesh (SUST).
 

Watch out for my other CodeProject Articles.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 3memberPriyank Bolia28 Jul '10 - 0:22 
The article doesn't contain anything new and there are article on the internet which are more detailed and simple. Also this XPCOM component won't work with latest Firefox. There are so many registration changes. I expected anything new in an article from what is already there on other websites.
GeneralRe: My vote of 3 PinmemberMd. Mazharul Islam Khan28 Jul '10 - 18:30 
I wonder how you rated 3.
 
1. My article is for the xpcom beginners. you already know many of xpcom. so, you think that no new things in the article. do you find any article like this in codeproject?
2. ya, there are so many articles in the web. but when i read those article i had to face some problems. so, i tried to clear it.
3. I wrote that, select the correct sdk. so, your sdk and firefox version aren't compatible.
GeneralRe: My vote of 3 PinmemberAnatoly Kirsanov28 Jul '10 - 21:45 
Would you give me some links? I faced with problems using this article
GeneralRe: My vote of 3 PinmemberPriyank Bolia28 Jul '10 - 21:53 
I had written code using this:
http://www.iosart.com/firefox/xpcom/[^]
Mozilla site is also good for referring:
https://developer.mozilla.org/en/XPCOM[^]
 
But, if you are looking for Firefox 4, then I suppose you have to wait, as the SDK is not ready, and I am facing lot of issues with the beta SDK.

GeneralRe: My vote of 3 PinmemberAnatoly Kirsanov28 Jul '10 - 22:45 
Thanks. What files for SDK (Windows) do you really download?
 
I followed to http://ftp.mozilla.org/pub/mozilla.org/mozilla/releases/mozilla1.7/[^] as was told in http://www.iosart.com/firefox/xpcom/[^]/
 
Then I downloaded gecko-sdk-i586-pc-msvc-1.7.zip but xpidl needs libIDL-0.6.dll which is not in this archive. To find it I downloaded mozilla-win32-1.7.zip The same problem - libIDL-0.6.dll is absent.
 
I tried to use mozilla-win32-1.7.zip instead of gecko-sdk-i586-pc-msvc-1.7.zip but it does not contain any idl folder.
GeneralRe: My vote of 3 PinmemberPriyank Bolia28 Jul '10 - 22:59 
If you read it fully or use google search, you can find people have already written solutions for that issue:
read the Jan Wagner comment there or read this article: http://mozilla-firefox-extension-dev.blogspot.com/2004/11/find-xpidlexe-in-gecko-sdk-for.html[^]. I wrote the plugin 2 years back, so I don't remember the exact steps. But that had sufficient knowledge to get started.

GeneralRe: My vote of 3 PinmemberMd. Mazharul Islam Khan28 Jul '10 - 22:50 
1. can u find any article which implement xmcom component in c++ project?
2. can u register ur xpcom dll, using ur link using regxpcom commnand?
http://www.iosart.com/firefox/xpcom/[^]
 
it stated that
"You might need to provide an additional parameter:
regxpcom -x _COMPONENTS_DIR_ where _COMPONENTS_DIR_ is the components directory.
Delete the xpti.dat and compreg.dat files from your Mozilla profile directory.
These files will be automatically rebuilt by Mozilla the next time it is restarted."
 
but in reality, u have to delete those files first. then use regxpcom command or restart firefox.
 
I am mentioning again. this article for the beginners.
GeneralRe: My vote of 3 PinmemberPriyank Bolia28 Jul '10 - 23:03 
I don't think regxpcom is needed, creating a component directly under the plugin, works. Just copy your dll to that component folder.
Also all of these is obsolete, that's one of the reason you got a 3. In the latest Firefox 4, you need to add binary-component to your chrome.manifest

GeneralRe: My vote of 3 PinmemberMd. Mazharul Islam Khan3 Aug '10 - 0:57 
You don't think regxpcom is needed. So sad. But using regxpcom is the main way to register xpcom.
Restarting FF, also did that for you.
GeneralRe: My vote of 3 PinmemberPriyank Bolia3 Aug '10 - 1:11 
You mean to run regxpcom on customer machine. I think regxpcom is needed when you don't have an addon that the xpcom component is part of. Normally you write xpcom to be part of some addon, so as I said, I just put them in the component directory of my addon with the xpt file, and delete the xpti.dat and compreg.dat.
I guess regxpcom is used in development environment, because the path of the xpcom dll might be your debug folder, rather than the addon component folder. But I just copy the dll to component folder and manually restart the firefox.
Also I am not sure whether regxpcom will work with the Gecko 2 SDK.

GeneralRe: My vote of 3 PinmemberMd. Mazharul Islam Khan3 Aug '10 - 2:29 
Oh. no.. My article is for xpcom programmers, not for xpcom plugin users. For xpcom plugin users, that is customer, there must be installation file which will delete xpti.dat and compreg.dat, modify components.list and then run regxpcom command.
GeneralRe: My vote of 3 PinmemberAnatoly Kirsanov29 Jul '10 - 0:18 
Priyank Bolia wrote:
I had written code using this:
http://www.iosart.com/firefox/xpcom/[^]

 
This article is bad for novice too. I had to copy some libs to build successfully from xulrunner-sdk-1.9.2.8 (nspr4.lib, plc4.lib, plds4.lib). But test page yields "TypeError: Components.classes[cid] is undefined".
 
Some humor I found http://mozilla-firefox-extension-dev.blogspot.com/2004/11/find-xpidlexe-in-gecko-sdk-for.html[^] Frown | :(
 
posted by David Huynh at 1:42 PM November 14, 2004
Isn't Open Source wonderful? All the information you need is out there, all for free. You just need to spend 20 hours to find them, and your life has just been reduced by 40 days due to frustration. By the end of those 20 hours, you can't even remember what you initially set out to do.

GeneralRe: My vote of 3 PinmemberPriyank Bolia29 Jul '10 - 0:43 
I don't know about xulrunner_sdk, but the article was written long back, and the gecko-sdk that I have contains all the necessary files like libIDL-0.6.
 
And for the humor part, I myself trying for the last 48 hours to get XPCOM work on Firefox 4b2, which has changed the XPCOM registration altogether, and I am happy that Firefox is open source, extracting information from ... is even harder, and writing a plugin for IE is more harder at least for me.

GeneralRe: My vote of 3 PinmemberMd. Mazharul Islam Khan28 Jul '10 - 22:56 
Better u should send me some of the links where u found xpcom better explained sothat i can learn.
 
why do i blame others' article?

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 1 Jul 2010
Article Copyright 2010 by Md. Mazharul Islam Khan
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid