Tuesday, November 2, 2010

Creating C++ Component / Interface of Firefox Using Gecko-SDK

This is step-by-step guide to create, build, register and use a XPCOM component/Interface on Linux (Ubuntu)

A. Creating A Component
Step 1: Download Gecko SDK (gecko-sdk-i686-pc-linux-gnu-X.X.X.X) and Extract it to local directory  "gecko-sdk".
Step 2: Use a utility "uuidgen" to generate UUID for our main Interface.
Step 3: Create an Interface defination file "KFFComponent.idl", use following template, simply replace uuid(1c0856f7-ed61-471e-9dac-442565a5d1d2) with your unique uuid(your_UUID) field.


#include "nsISupports.idl"
[scriptable, uuid(1c0856f7-ed61-471e-9dac-442565a5d1d2)]
interface KFFComponent : nsISupports
{
  unsigned long long Add(in unsigned long long num1, in unsigned long long num2);
  unsigned long long Sub(in unsigned long long num1, in unsigned long long num2);
};

Step 4: Open command prompt and go to "gecko-sdk/bin" and run following command:
$ ./xpidl  -m  header  -I_DIR_    KFFComponent.idl

Replace "_DIR_" with the full path to the "gecko-sdk/idl". Above command will create "KFFComponent.h" header file.

Step 5: Now to create typelib file, execute following command
$ ./xpidl  -m  typelib  -I_DIR_   KFFComponent.idl
Replace "_DIR_" with the full path to the "gecko-sdk/idl". Above command will create  "KFFComponent.xpt" typelib file

Step 6: Interface header file contains the template for building our component header file as well as C++ Implementation file.

Step 7: Create our own component Header file "krpComponent.h", use following contents:

#ifndef _KRP_COMPONENT_H_
#define _KRP_COMPONENT_H_
#include "KFFComponent.h"
#define KRP_COMPONENT_CONTRACTID "@mydomain.com/XPCOMSample/krpComponent;1"
#define KRP_COMPONENT_CLASSNAME "First XPCOM Sample Interface"
#define KRP_COMPONENT_CID {0x462EF8EF, 0x9A05, 0x49DE, {0x97, 0xAC, 0x82, 0x2A, 0x6C, 0x46, 0xD2, 0xDC } }


/* KRP_COMPONENT_CID = GUID (462EF8EF-9A05-49DE-97AC-822A6C46D2DC)
    Note: Replace GUID with your own GUID field
*/
/* Header file */
class krpComponent : public KFFComponent
{
public:
  NS_DECL_ISUPPORTS
  NS_DECL_KFFCOMPONENT
  krpComponent();
private:
  ~krpComponent();
protected:
  /* additional members */
};
#endif  /* end of _KRP_COMPONENT_H_ */

Step 8: Create our won C++ Implementation file for the Componenet "krpComponent.cpp".

#include "krpComponent.h"
/* Implementation file */
NS_IMPL_ISUPPORTS1(krpComponent, KFFComponent)
krpComponent::krpComponent()
{
  /* member initializers and constructor code */
}
krpComponent::~krpComponent()
{
  /* destructor code */
}
/* unsigned long long Add (in unsigned long long num1, in unsigned long long num2); */
NS_IMETHODIMP krpComponent::Add(PRUint64 num1, PRUint64 num2, PRUint64 *_retval)
{
  *_retval = num1 + num2;
  return NS_OK;
}
/* unsigned long long Sub (in unsigned long long num1, in unsigned long long num2); */
NS_IMETHODIMP krpComponent::Sub(PRUint64 num1, PRUint64 num2, PRUint64 *_retval)
{
  *_retval = num1 - num2;
  return NS_OK;
}
/* End of implementation class template. */

Step 9: Create our own Module definition file "krpComponentModule.cpp".
// This is necessary file to include Mozill Generic definations
#include "nsIGenericFactory.h" 
//My Component Header File 
#include "krpComponent.h" 
NS_GENERIC_FACTORY_CONSTRUCTOR(krpComponent)
static nsModuleComponentInfo components[] =
{
    {
       KRP_COMPONENT_CLASSNAME, 
       KRP_COMPONENT_CID,
       KRP_COMPONENT_CONTRACTID,
       krpComponentConstructor,
    }
};
NS_IMPL_NSGETMODULE("krpComponentsModule", components) 

B: Building our Component / Interface
Step 1: Create Makefile or use your own template
CXX   = c++
CPPFLAGS +=     -fno-rtti              \
-fno-exceptions        \
-shared  
# Change this to point at your Gecko SDK directory. 
GECKO_SDK_PATH = /home/username/cprogs/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 = krpComponent.cpp krpComponentModule.cpp 
TARGET = krpComponent.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)

Step 2: Run "make" command, and it "krpComponent.so" file will be created.

C: Registering the Component
Step 1: Copy krpComponent.so and KFFComponent.xpt file to "~/.mozilla/component" directory
Step 2: use command "regxpcom" to register component
$ ./regxpcom  -x  _DIR_PATH_OF_COMPONENT_
 Replace _DIR_PATH_OF_COMPONENT with the path of component (krpComponent.so)
Step 3: Restart Mozilla.

D: Testing Component
You can either use Extension or HTML page to test our new Firefox C++ Component.
HTML Code of "TestComponent.html" page is as follows



<script>
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const cid = "@mydomain.com/XPCOMSample/krpComponent;1";
var obj = Components.classes[cid].createInstance();
var obj1 = obj.QueryInterface(Components.interfaces.KFFComponent);

               var res = obj1.Sub(10, 5);
alert('Performing 10 - 5  =  ' +  res );

} catch (err) {
alert(err);
}

</script>


1 comment:

  1. I have used same code given at yr website for windows and try to generate dll in visual studio 8. but it gives me error like this
    1.Error 5 error LNK2028: unresolved token (0A00002E) "unsigned int __stdcall NS_TableDrivenQI(void *,struct QITableEntry const *,struct nsID const &,void * *)" (?NS_TableDrivenQI@@$$FYGIPAXPBUQITableEntry@@ABUnsID@@PAPAX@Z) referenced in function "public: virtual unsigned int __stdcall krpComponent::QueryInterface(struct nsID const &,void * *)" (?QueryInterface@krpComponent@@$$FUAGIABUnsID@@PAPAX@Z) XpcombyneelamCom.obj XpcombyneelamCom

    2.Error 6 error LNK2019: unresolved external symbol "unsigned int __stdcall NS_TableDrivenQI(void *,struct QITableEntry const *,struct nsID const &,void * *)" (?NS_TableDrivenQI@@$$FYGIPAXPBUQITableEntry@@ABUnsID@@PAPAX@Z) referenced in function "public: virtual unsigned int __stdcall krpComponent::QueryInterface(struct nsID const &,void * *)" (?QueryInterface@krpComponent@@$$FUAGIABUnsID@@PAPAX@Z) XpcombyneelamCom.obj XpcombyneelamCom
    3.

    Error 7 fatal error LNK1120: 2 unresolved externals C:\Neelam\XpcombyneelamCom\Debug\XpcombyneelamCom.dll XpcombyneelamCom

    ReplyDelete