Implementing XPCOM Objects

Implementing XPCOM Objects

Adding Interface Support

Example 1. part of nsIFactory implementation

  class Factory
    include XPCOM::QueryInterfaceBasic
    support "nsIFactory"

    def initialize(klass)
      @klass = klass
    end

    def createInstance(outer, iid)
      unless outer.nil?
        raise "aggregation is not supported"
      end

      @klass.new.QueryInterface(iid) or 
        raise(XPCOMError, "component does not support #{iid}")
    end
  end
    

Above code is taken from the implementation of nsIFactory used in the component loader. The rest of Factory are plain old Ruby class definition. non idl method (like initialize) can be defined. Not all idl methods are needed to be defined (a call for undefined method will fail gracefully).

In order to support a XPCOM idl interface, a ruby object must respond to QueryInterface method. The module XPCOM::QueryInterfaceBasic provides a basic implementation of this method. Include this module into your class and declare supported interface by class method support.

include XPCOM::QueryInterfaceBasic
support "nsIFactory"
     

Since nsIFactory inherits from nsISupports, Above Factory supports nsISupports as well.

Sub classes inherit support of the interfaces from its parent.

# Foo supports nsIFactory
class Foo < Factory
end
     

QueryInterface defined by XPCOM::QueryInterfaceBasic always returns self for a supported interface (that should be ok for the majority of cases).

Any object respond to QueryInterface can be used as XPCOM component, except nil (mapped to NULL pointer), true, false, FIXNUM, SYMBOL (due to imcompatible identity mechanism).

Registering Component

XPCOM.register method is used to register a component to ComponentManager. Only component registered to ComponentManager can be instantiated by XPCOM.instance (and other language's counterpart).

XPCOM.register is called like this.

 XPCOM.register(RbXPCOMTestImpl,
                 XPCOM::ID.new("{121bec1c-20be-433b-b153-9edd508a8300}"),
                 "rbXPCOMTest in ruby",
                 "@ruby/test/TestRuby;1")
     

See the reference for additonal info. The implementation of the component loader(xpcom/loader.rb) does somethign tricky to bootstrap the loader. It's not a good example for XPCOM.register.