Setting up the Gecko SDK with Visual Studio 2010

When you want to get started with the Gecko SDK to build your first binary HelloWorld XPCOM component you likely stumble upon this page in the MDN describing how to do that. Unfortunately it is not up to date. The changes introduced with Gecko 2.0 can be found here.

The necessary steps to set up a development environment for a C++ XPCOM component in Visaual Studio 2010 require to adapt the right things from both articles, so here we go.

1. Download the Gecko SDK

From the Gecko SDK page choose the version for which you want to develop your component and extract the archive to some folder, e.g. C:\XPCOM, which I’ll use throughout this article.

A list of all released SDK versions can found here. Since Gecko 2.0, SDK version and application version match, at least for Firefox and Thunderbird.

2. Create the Visual C++ project

In VS 2010 create a new project using the Win32 Console Application template, call it „HelloWorld“ and set C:\XPCOM as its location. In the following dialog set the type to DLL and choose „Empty Project“ under additional options.

Configure Includes and Libraries

Next open the properties dialog for the new project. Switch to the VC++-Directories entry and add ‚..\..\xulrunner-sdk\include;‚ (assuming the solution and SDK folders are in the same directory) before the $(IncludePath) already there in Include Directories.

Then switch to the Linker entry and set ‚..\..\xulrunner-sdk\lib‚ as Additional Library Directories. Afterwards go to the Linker’s Input sub-entry and add the following Additional Dependencies: ‚nspr4.lib;xpcom.lib;xpcomglue_s.lib;mozalloc.lib

3. Prepare the XPIDL interface and a Pre-build event

The starting point for a binary XPCOM component is its XPIDL definition (how and why is out of scope here, but you may read this and that for more details). I used the sample from here but used IHelloWorld as its name.

Create the file IHelloWorld.idl in C:\XPCOM\HelloWorld\HelloWorld with the following content:

#include "nsISupports.idl"

[scriptable, uuid(2f52e0f0-0eac-11e1-be50-0800200c9a66)]
interface IHelloWorld : nsISupports
{
    attribute AString name;
    long add(in long a, in long b);
}

Then create ‚xpidl-build.bat‘ in the same directory with the following two lines in it:

..\..\xulrunner-sdk\sdk\bin\xpidl.exe -m header -I..\..\xulrunner-sdk\idl %1
..\..\xulrunner-sdk\sdk\bin\xpidl.exe -m typelib -I..\..\xulrunner-sdk\idl %1

Go back to the properties dialog of the VS 2010 project and navigate to Build Events and add ‚xpidl-build.bat IHelloWorld.idl‚ as Command Line call to the Pre-Build Event. This will trigger the xpidl tool to create the header and typelib files from the latest version of the XPIDL definition before the actual compilation.

4. Create the C++ header and implementation files

Select „Build“ from the project’s context menu to trigger the script or create the header and typelib manually. Then add the IHelloWorld.h header file from the step before to the project.

The end of this header file contains the templates for another header file, HelloWorld.h and an implementation file, HelloWorld.cpp, which make up the actual implementation of the interface. Create them and copy the respective part of the template into them and replace all occurrences of _MYCLASS_ by HelloWorld.

Now open the properties dialog of the project again and add XP_WIN, XP_WIN32, XPCOM_GLUE and MOZILLA_STRICT_API to the Preprocessor Definitions in the C/C++ entry which wasn’t there before.

Add missing Defines and Includes

The project now knows all makros which are required to work with the Gecko SDK. But there are still some things missing in the HelloWorld.h and HelloWorld.cpp files. Make them look like this (and yourself understand what the additional lines are good for):

  1. #ifndef _HELLOWORLDT_H_
  2. #define _HELLOWORLD_H_
  3. #include "IHelloWorld.h"
  4. #include "nsStringAPI.h"
  5.  
  6. #define HELLOWORLD_CONTRACTID "@peschla.net/HelloWorld/HelloWorld;1"
  7. #define HELLOWORLD_CLASSNAME "HelloWordlSample"
  8. #define HELLOWORLD_CID  { 0x859b3230, 0x1034, 0x11e1, { 0xbe, 0x50, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
  9.  
  10. class HelloWorld : public IHelloWorld
  11. {
  12.   private:
  13.     nsString mName;
  14.   public:
  15.     NS_DECL_ISUPPORTS
  16.     NS_DECL_IHELLOWORLD
  17.     HelloWorld();
  18.  
  19.   virtual ~HelloWorld();
  20. };
  21. #endif //_HELLOWORLD_H_
  1. #include "HelloWorld.h"
  2.  
  3. NS_IMPL_ISUPPORTS1(HelloWorld, IHelloWorld)
  4.  
  5. HelloWorld::HelloWorld()
  6. {
  7.     mName.Assign(L"Nameless");
  8. }
  9.  
  10. HelloWorld::~HelloWorld(){}
  11.  
  12. /* attribute AString name; */
  13. NS_IMETHODIMP HelloWorld::GetName(nsAString & aName)
  14. {
  15.     aName.Assign(mName);
  16.     return NS_OK;
  17. }
  18.  
  19. NS_IMETHODIMP HelloWorld::SetName(const nsAString & aName)
  20. {
  21.     mName.Assign(aName);
  22.     return NS_OK;
  23. }
  24.  
  25. /* long add (in long a, in long b); */
  26. NS_IMETHODIMP HelloWorld::Add(PRInt32 a, PRInt32 b, PRInt32 *_retval NS_OUTPARAM)
  27. {
  28.     *_retval = a + b;
  29.     return NS_OK;
  30. }

The module code

The previous steps are still like described in this article. But for the module, which is the entry point to access the component (more on that here), the changes mentioned here have to be followed.

On the basis of Mozilla’s example in nsSampleModule.cpp the code for the module can be derived. Add it as HelloWorldModule.cpp to the project:

  1. #include "mozilla/ModuleUtils.h"
  2. #include "nsIClassInfoImpl.h"
  3. #include "HelloWorld.h"
  4.  
  5. NS_GENERIC_FACTORY_CONSTRUCTOR(HelloWorld)
  6.  
  7. // The following line defines a kHELLOWORLD_CID CID variable.
  8. NS_DEFINE_NAMED_CID(HELLOWORLD_CID);
  9.  
  10. static const mozilla::Module::CIDEntry kSampleCIDs[] = {
  11.      { &kHELLOWORLD_CID, false, NULL, HelloWorldConstructor },
  12.         { NULL }
  13. };
  14.  
  15. static const mozilla::Module::ContractIDEntry kSampleContracts[] = {
  16.      { HELLOWORLD_CONTRACTID, &kHELLOWORLD_CID },
  17.      { NULL }
  18. };
  19.  
  20. static const mozilla::Module kSampleModule = {
  21.      mozilla::Module::kVersion,
  22.      kSampleCIDs,
  23.      kSampleContracts,
  24.      NULL /* or a category definition if you need it */
  25. };
  26.  
  27. NSMODULE_DEFN(nsSampleModule) = &kSampleModule;

Final Remarks

If you know build the project you’ll get your DLL file in the output directory of the active configuration. Together with the corresponding typelib, IHelloWorld.xpt in this case, you now can use the component in an extension. How the registration of both works is also explained in the „changes“ article on MDN.

Don’t forget that the component has to be compiled for each platform on which it is supposed to be supported/executed.

Comments (16)

MarekDezember 22nd, 2011 at 13:51

Starting with Gecko 9.0, the gecko-sdk does not contain the xpidl.exe file.

Does anyone know, what is its replacement, when I build XPCOM component on Windows?

jonasDezember 22nd, 2011 at 15:13

It probably is a good idea to ask in the Mozilla IRC channels (https://wiki.mozilla.org/IRC) for that. I would start asking in #developers.

Where do you have this information from? Are you sure that it won’t come in later – Gecko 9 is still under development according to the respective page on MDN.

MarekDezember 22nd, 2011 at 16:54

Gecko 9 is out since last week together with Firefox 9.0.

In our company, we have a small XPCOM Component for intranet puropses. When trying to build it with Gecko 9, I have found out that xpidl.exe is not there.

MarekJanuar 5th, 2012 at 17:09

According to mozilla documentation, the XPIDL utility was replaced by PYXPIDL.

See also https://developer.mozilla.org/en/XPIDL/pyxpidl

You must have Python installed on your computer to run the python scripts contained in pyxpidl. A good solution for me was to use PortablePython.

Note: Version 2.7.* must be used to run the pyxpidl scripts. Version 3.5 reports syntax errors.

GoargeJuli 4th, 2013 at 16:12

Please help with this.
I have followed your step but I am getting following error :
Error 1 error MSB3073: The command „xpidl-build.bat IHelloWorld.idl
:VCEnd“ exited with code 1. C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets 103 6 HelloWorld

Stefan WintersteinNovember 18th, 2014 at 13:06

I managed to get it to work in VS 2013 and using XULRunner 29, so here’s the 2014 update:

* Step 2: Also add „xulrunner-sdk\include\nspr“ to include directoris. For linker libraries, link to xul.lib instead of xpcom.lib

* Step 3: Add „;“ at end of IHelloWorld.idl. „xpidl.exe“ has been replaced by a Python script. My new „xpidl-build.bat“ looks like this:

=======
set PYTHON=D:\dev\python-2.7\App\python.exe
set XULSDK=C:\dev\xulrunner-29.0b9\obj-i686-pc-mingw32\xulrunner\dist

:: .xpt file
%PYTHON% %XULSDK%\sdk\bin\typelib.py -o %1.xpt -I %XULSDK%\idl %1.idl

:: .h file
%PYTHON% %XULSDK%\sdk\bin\header.py -o %1.h -I %XULSDK%\idl %1.idl
=======

* Step 4: At the start of every .cpp file, add
=======
#include
=======

Okay, that’s it for the changes. I’ve uploaded a .zip file with the VC project here:
https://www.dropbox.com/s/1ymt2wxwd0y4v0t/helloworld.zip?dl=0

This also includes a directory for Firefox extension deployment, which contains a chrome.manifest and install.rdf file. After compiling, copy „Debug\HelloWorld.dll“ and „.\IHelloWorld.xpt“ manually to „Extension/components“. Then zip the contents inside the Extension directory to a file and rename it to „HelloWorld.xpi“. This file can then be dropped into Firefox to install the extension. Test it by going to „chrome://helloworld/content/HelloWorldTest.html“.

Good luck!

Ashish SonawaneDezember 29th, 2014 at 15:40

Hi,
@Stefan Winterstein I am trying to build your code but getting this error.

„Error 1 error MSB3073: The command „xpidl-build.bat IHelloWorld
:VCEnd“ exited with code 2. “

can you please help..

Ashish SonawaneDezember 30th, 2014 at 12:02

Hi,

@Stefan
Now I am able to build the component but after installation on extension it giving error that „Con not initialize XPCOMP interface Components.classes is undefined. “

can you please help..

Andrew PolarJanuar 5th, 2015 at 20:26

This site pretends to be an easy and quick introduction in building xpcom dll but it is actually as useless as any other site. When following the instructions problems are emerging one after another. After spending an hour for solving one problem you simply stumble on another.
1. The file xpidl.exe can be downloaded with Gecko 1.7.* after I copied it into mozilla folder
C:\Users\AP250406\XUL\mozilla-win32-1.7rc2\mozilla
it started complaining on missing dll, which I downloaded from
https://developer.mozilla.org/en/docs/How_to_build_a_binary_XPCOM_component_using_Visual_Studio
link wintools.zip.
Now it does not like this „%{C++“ in file nsrootidl.idl.
I’ve spent 3 years making COM application, I’ve edited manually *.idl files and I’ve never seen combinations %{C++ in them. Why everyone in the world tries to customize everything. Who knows what %{C++ is how it is ended in *.idl file, please reply.

Andrew PolarJanuar 5th, 2015 at 21:54

I found that many people posted questions about %{C++ expression in *.idl files. And another large group of people provide incompetent answers. The problem is that IHelloWorld.idl should not be included into visual studio project. When it is included the VS starts MIDL compiler that does not recognize %{C++ expression. After excluding this file from project this bug was gone.
My previous comment shows how to use xpidl.exe without python. Now I passed that stage and fighting new set of compiling errors of IHelloWorld.h. They are mostly concerns undefined macros.
I think the world needs another site after this supposed to be „explain everything“ site, which explains what this site failed to explain.
Why it is so hard for people to show working HelloWorld extension?

Andrew PolarJanuar 5th, 2015 at 23:43

It compiled after I rolled from version 1.9 to 1.8.
I dropped postfix NS_OUTPARAMS in HelloWorld.cpp, same as it is shown in
http://www.codeproject.com/Articles/87465/A-Simple-XPCOM-Tutorial
That is not the end of the story, registering and running will bring more issues.
I found 3 things that make following this article to last a day instead of 15 minutes.
1. You should use version 1.8, not the other.
2. You should find and copy 2 dlls glib-1.2.dll and libIDL-0.6.dll where xpidl.exe is sitting.
3. You should drop NS_OUTPARAM in HelloWorld.cpp.

jonasJanuar 6th, 2015 at 05:08

Well, maybe, just as a sugestion, things aren’t up to date because this post deals with Gecko as of end of 2011 and just maybe there have been some changes within the last ~3 years. I would at least consider this as an option.

Andrew PolarJanuar 6th, 2015 at 16:50

You can clarify few things:
When adding IDL file shown above to Visual Studio, it should be excluded from build. Because when IDL file is included into VS, it automatically invoke MIDL compiler, that is microsoft compiler. For firefox extension MIDL is replaced by XPIDL. It starts by xpild.exe from batch file, shown in article and carries same functions as MIDL – it generates code and library. That explains other things with python script, which is other form of starting XPIDL and result must be same code and library generation. In your explanation you advice to make batch file and execute it in prebuild, which is correct but you not explain what is that for.
Actually they did not change much in 2.0. Using python is not a problem.

Andrew PolarJanuar 12th, 2015 at 00:15

I’m still fighting errors. The example of
Stefan WintersteinNovember 18th, 2014 at 13:06
which works for version 29 does not work for latest version of FF. The problem is in linking. It looks like library xpcomglue_s.lib is compiled with settings that contradict VS2013 and VS2010. I need either to disassemble is and fix binary or recompile entire xulrunner code.

Andrew PolarJanuar 12th, 2015 at 05:49

SUCCESS
Finally I made it running. There are few things that I’ve added to this version
Stefan WintersteinNovember 18th, 2014 at 13:06
1. When using VS2013 make settings: Config Properties->General->Platform Toolset and choose VS2010(v100).
2. Add this
_ITERATOR_DEBUG_LEVEL=0
to preprocessor definitions.
3. Open Mozilla profile folder and clean previous version of extenstions, because when you added extension with the bug and then removed it, it was not actually removed. The profile folder can be found by using Mozilla help (Troubleshooting information, profile button).

I know it is hard to follow what I write, so I can answer questions:
andrewpolar@bellsouth.net

AnonymousFebruar 2nd, 2015 at 12:23

LOL. Where is the SUCCESS? 🙂
You compiling using VS2010 which means you have to install it on your computer.

Leave a comment

Your comment

(required)