Como construir um componente XPCOM em Javascript

by 1 colaborador:

Este é um tutorial "Olá Mundo" para a criação de um componente XPCOM em JavaScript. Este tutorial não descreve como e por que XPCOM funciona da maneira que faz, ou o que cada bit do código de exemplo faz. Isso foi detalhado em outro lugar. Este tutorial irá mostrar-lhe o que você precisa fazer para obter um componente de trabalho como poucos e como passos mais simples possível.

Implementação

Este componente exemplo, irá expor um único método, que retorna a string "Olá Mundo!".

Definindo a Interface

Se você quiser usar o componente em outras componentes XPCOM, você deve definir as interfaces que você deseja expor. Se você quiser usar o seu único componente de JavaScript, você pode pular para a próxima seção.

muitas interfaces definidas nos aplicativos Mozilla, então você pode não precisar de definir um novo. Você pode procurar as interfaces XPCOM existentes em vários locais no código fonte Mozilla, ou usando XPCOMViewer, uma interface gráfica para navegar interfaces e componentes registrados. Você pode baixar uma versão antiga do XPCOMViewer que funciona com Firefox 1.5 a partir de mozdev mirrors.

Se existe uma interface que atenda às suas necessidades, então você não precisa escrever uma IDL, ou compilar uma biblioteca de tipos, e pode pular para a próxima seção.

Se você não encontrar uma relação pré-existente adequada, em seguida, você deve definir o seu próprio. XPCOM usa um dialeto do IDL para definir interfaces, chamada XPIDL. Aqui está a definição XPIDL para o nosso componente Olá Mundo:

HelloWorld.idl

#include "nsISupports.idl"

[scriptable, uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)]
interface nsIHelloWorld : nsISupports
{
  string hello();
};  

Observe que você deve gerar um novo UUID para cada componente XPCOM que você criar. ver Generating GUIDs para mais informações.

Compilando o Typelib

Sua definição de interface deve ser compilado em um formato binário (XPT), a fim de ser registrado e usado em aplicativos Mozilla. A compilação pode ser feito usando o Gecko SDK. Você pode aprender como obter Mac, Linux e versões do Windows do Gecko SDK lendo o artigo Gecko SDK.

Para o código de fora da árvore

Nota: No Windows, se você baixar o Gecko SDK, sem toda a árvore de criação, você vai estar faltando algumas DLLs necessárias para xpidl.exe e ele será executado sem erros, mas não fazer nada. Para corrigir esta transferência o Mozilla build ferramentas para Windows e copiar as DLLs do windows \ bin \ x86 dentro do zip para o diretório bin do Gecko SDK.
Nota: A versão Mac do SDK fornecido para download é apenas para PowerPC. Se você precisa de uma versão Intel, você precisa compilá-lo como descrito na página.

Executar este comando para compilar o typelib. Aqui, {sdk_dir} é o diretório no qual você descompactou o Gecko SDK.

{sdk_dir}/bin/xpidl -m typelib -w -v -I {sdk_dir}/idl -e HelloWorld.xpt HelloWorld.idl
Nota: No Windows, você deve usar barras para o caminho de inclusão.
Nota: (o -I flag é um uppercase i, não é um lowercase L.)

Isto irá criar o arquivo HelloWorld.xpt typelib no diretório de trabalho atual.

Para um novo componente em Firefox/Thunderbird/B2G

Se você estiver adicionando uma nova funcionalidade para aplicações no repositório mozilla-central, você pode criar um Makefile listando os arquivos IDL e o sistema de compilação irá gerar automaticamente o typelib. A amostra Makefile.in

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@

include $(DEPTH)/config/autoconf.mk


# MODULE specifies where header files from this Makefile are installed
# Use dom if your component implements a DOM API
MODULE = dom

# Name of the typelib
XPIDL_MODULE = dom_apps

# Set to 1 if the module should be part of the Gecko Runtime common to all applications
GRE_MODULE = 1

# The IDL sources
XPIDLSRCS = \
 HelloWorld.idl \
 $(NULL)

include $(topsrcdir)/config/rules.mk

XPIDL_FLAGS += \
 -I$(topsrcdir)/dom/interfaces/base \
 -I$(topsrcdir)/dom/interfaces/events \
 $(NULL)

Criando o componente usando XPCOMUtils

em Firefox 3 e mais tarde você pode usar importação XPCOMUtils.jsm utilização Components.utils.import para simplificar o processo de escrever o seu componente ligeiramente. A biblioteca importada contém funções para gerar o módulo, a fábrica, e os NSGetModule e QueryInterface funções para você. Nota: ele não faz o trabalho de criar o arquivo de definição de interface ou a biblioteca de tipos para você, então você ainda tem que passar por essas etapas anteriores, caso não tenham sido feito. A biblioteca proporciona um exemplo simples de sua utilização no código fonte (js/src/xpconnect/loader/XPCOMUtils.jsm), mas aqui é outro usando este exemplo. Para começar, inclua uma linha no topo da sua interface para importar a biblioteca XPCOMUtils:

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");

em seguida, implementar a interface da mesma forma que fiz acima, exceto com algumas modificações para que XPCOMUtils pode configurá-lo corretamente:

/***********************************************************
class definition
***********************************************************/

//class constructor
function HelloWorld() {
// If you only need to access your component from Javascript, uncomment the following line:
//this.wrappedJSObject = this;
}

// class definition
HelloWorld.prototype = {

  // properties required for XPCOM registration:
  classDescription: "My Hello World Javascript XPCOM Component",
  classID:          Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
  contractID:       "@dietrich.ganx4.com/helloworld;1",

  // [optional] custom factory (an object implementing nsIFactory). If not
  // provided, the default factory is used, which returns
  // |(new MyComponent()).QueryInterface(iid)| in its createInstance().
  _xpcom_factory: { ... },

  // [optional] an array of categories to register this component in.
  _xpcom_categories: [{

    // Each object in the array specifies the parameters to pass to
    // nsICategoryManager.addCategoryEntry(). 'true' is passed for both
    // aPersist and aReplace params.
    category: "some-category",

    // optional, defaults to the object's classDescription
    entry: "entry name",

    // optional, defaults to the object's contractID (unless 'service' is specified)
    value: "...",

    // optional, defaults to false. When set to true, and only if 'value' is not
    // specified, the concatenation of the string "service," and the object's contractID
    // is passed as aValue parameter of addCategoryEntry.
     service: true
  }],

  // QueryInterface implementation, e.g. using the generateQI helper (remove argument if skipped steps above)
  QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIHelloWorld]),

  // Optional, but required if you want your component to be exposed to DOM
  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
                                    contractID: "@dietrich.ganx4.com/helloworld;1",
                                    interfaces: [Ci.nsIHelloWorld],
                                    flags: Ci.nsIClassInfo.DOM_OBJECT}),

  // ...component implementation...
  // define the function we want to expose in our interface
  hello: function() {
      return "Hello World!";
  },
};

XPCOMUtils faz o trabalho de criação do módulo e da fábrica para você depois disso. Finalmente, você cria uma matriz de seus componentes a serem criados:

 var components = [HelloWorld];

e substituir NSGetFactory / NSGetModule usar essa matriz e XPCOMUtils:

 if ("generateNSGetFactory" in XPCOMUtils)
   var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);  // Firefox 4.0 and higher
 else
   var NSGetModule = XPCOMUtils.generateNSGetModule(components);    // Firefox 3.x

Assim, a versão simplificada do total de seu componente agora parece (é claro que a documentação e os comentários não são uma coisa ruim, mas como um modelo algo menor é bom ter):

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");

function HelloWorld() { }

HelloWorld.prototype = {
  classDescription: "My Hello World Javascript XPCOM Component",
  classID:          Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
  contractID:       "@dietrich.ganx4.com/helloworld;1",
  QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIHelloWorld]),
  hello: function() { return "Hello World!"; }
};
var components = [HelloWorld];
if ("generateNSGetFactory" in XPCOMUtils)
  var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);  // Firefox 4.0 and higher
else
  var NSGetModule = XPCOMUtils.generateNSGetModule(components);    // Firefox 3.x
Nota: A partir do Firefox 4.0 será necessário declarar o componente em chrome.manifest; classDescription e propriedades contractID por outro lado, não são mais necessários. ver XPCOM changes in Gecko 2.0 para mais detalhes.

Instalação

para extensões:

  1. Helloworld.js copiar e HelloWorld.xpt ( se você tiver definido e compilou o IDL) para {extensiondir}/components/.
  2. Excluir compreg.dat e xpti.dat do seu diretório de perfil.
  3. reinicie o aplicativo.

Para Firefox:

  1. Helloworld.js copiar e HelloWorld.xpt ( se você tiver definido e compilou o IDL) para o {objdir}/dist/bin/components directory, se correr a partir da fonte.
  2. Excluir compreg.dat e xpti.dat do diretório componentes.
  3. Excluir compreg.dat e xpti.dat do seu diretório de perfil.
  4. reinicie o aplicativo.

Usando o Componente

Usando wrappedJSObject

Se você só pretende aceder à sua componente de Javascript, ou seja, você pulou as seções "Definindo a Interface" e "Compilando o Typelib" acima, é comentada a linha "wrappedJSObject" no construtor da classe, e removido o "[Components.interfaces.nsIHelloWorld]" argumento para a chamada para XPCOMUtils.generateQI() em QueryInterface, então você pode acessar o seu componente da seguinte forma:

try {
        var myComponent = Components.classes['@dietrich.ganx4.com/helloworld;1']
                                    .getService().wrappedJSObject;

        alert(myComponent.hello());
} catch (anError) {
        dump("ERROR: " + anError);
}

Para mais informações sobre wrappedJSObject, veja aqui.

Usando instanciação XPCOM

try {
        var myComponent = Components.classes['@dietrich.ganx4.com/helloworld;1']
                                    .createInstance(Components.interfaces.nsIHelloWorld);

        alert(myComponent.hello());
} catch (anError) {
        dump("ERROR: " + anError);
}

Outros recursos

 

Tradução para o portugues(Brasil) : Josimar de souza

contato : portaldobarulho@hotmail.com

site : Portal do Barulho

Etiquetas do documento e colaboradores

Contributors to this page: portaldobarulho
Última atualização por: portaldobarulho,