Interfejsy XPCOM

This is an archived page. It's not actively maintained.

W tym artykule kr贸tko przyjrzymy si臋 XPCOM (Wieloplatformowy Model Obiekt贸w Sk艂adowych), kt贸ry jest systemem Object, jakiego u偶ywa Mozilla.

Wywo艂ywanie obiekt贸w wewn臋trznych

Przez zastosowanie XUL mo偶emy zbudowa膰 z艂o偶ony interfejs u偶ytkownika. Mo偶emy do艂膮czy膰 skrypty, kt贸re modyfikuj膮 interfejs i wykonuj膮 zadania. Jednak偶e, jest kilka rzeczy, kt贸rych nie mo偶na wykona膰 bezpo艣rednio w JavaScript. Na przyk艂ad, je艣li chcieliby艣my stworzy膰 aplikacj臋 pocztow膮 musieliby艣my napisa膰 skrypt, dzi臋ki kt贸remu po艂膮czymy si臋 z serwerem pocztowym dla wyszukania i wys艂ania mail. JavaScript nie ma mo偶liwo艣ci wykonania takich rzeczy.

Jedynym spos贸b wykonania tego by艂oby napisanie kodu wewn臋trznego, kt贸ry pobra艂by poczt臋. Musimy r贸wnie偶 posiada膰 spos贸b, aby w 艂atwy spos贸b nasze skrypty wywo艂ywa艂y kod wewn臋trzny Mozilla dostarcza takiej metody wymagaj膮cej zastosowania XPCOM(Wieloplaformowego modelu obiekt贸w sk艂adowych)

O XPCOM

Mozilla jest z艂o偶ona ze zbioru komponent贸w, ka偶dy wykonuj膮cy pewne zadanie. Na przyk艂ad jest komponent dla ka偶dego menu, przycisku i elementu. Komponenty s膮 z艂o偶one z kilku definicji nazywanych interfejsami Interfejs w Mozilli jest definicj膮 zbioru funkcjonalno艣ci, kt贸re mog膮 by膰 zaimplementowane przez komponenty.

Komponenty s膮 tym, co implementuje kod, w Mozilli dla wykonania r贸偶nych rzeczy. Ka偶dy komponent implementuje funkcjonalno艣膰 opisan膮 przez interfejsy. Pojedynczy komponent mo偶e zaimplementowa膰 wiele interfejs贸w. A wiele komponent贸w mo偶e zaimplementowa膰 ten sam interfejs.

We藕my za przyk艂ad komponent plik. Interfejs potrzebowa艂by opisu w艂a艣ciwo艣ci i funkcji, jakie mog膮 by膰 wykonywane na plikach. Plik potrzebuje w艂a艣ciwo艣ci dla swojej nazwy, daty modyfikacji i swojego rozmiaru. Funkcje pliku mog膮 obejmowa膰 jego przenoszenie, kopiowanie i usuwanie.

Interfejs Plik opisuje tylko cechy charakterystyczne pliku, nie implementuje go Implementacj臋 interfejsu Plik pozostawiono komponentowi. Komponent b臋dzie mia艂 kod, kt贸ry mo偶e odnale藕膰 nazw臋 pliku, dat臋 i rozmiar. Dodatkowo, b臋dzie mia艂 kod, kt贸ry kopiuje i zmienia jego nazw臋.

Nie musimy si臋 martwi膰 jak komponent go implementuje tak d艂ugo jak implementuje interfejs poprawnie. Oczywi艣cie, b臋dziemy mieli r贸偶ne implementacje, po jednej dla ka偶dej platformy Wersje komponentu plik dla Windows i Macintosh by艂yby znacz膮co r贸偶ne. Jednak obie implementuj膮 ten sam interfejs. A zatem mo偶emy u偶y膰 komponentu przez udost臋pnienie korzystania z funkcji, jakie znamy z interfejsu.

W Mozilli interfejsy s膮 poprzedzone, 鈥榥sI鈥 aby by艂y 艂atwo rozpoznawalne jako interfejsy. Na przyk艂ad nsIAddressBook jest to interfejs dla interaktywno艣ci z ksi膮偶ka adresow膮, nsISound jest u偶ywany do odgrywania plik贸w a nsILocalFile jest u偶ywany do plik贸w.

Komponenty XPCOM s膮 zazwyczaj zaimplementowane wewn臋trznie, co oznacza, 偶e generalnie wykonuj膮 rzeczy, kt贸rych nie mo偶e zrobi膰 sam JavaScript. Jednak spos贸b, w jaki mo偶na je wywo艂a膰 zobaczymy wkr贸tce. Mo偶emy wywo艂a膰 dowoln膮 funkcj臋 dostarczon膮 przez komponent, opisan膮 przez interfejsy go implementuj膮ce. Na przyk艂ad je艣li mamy komponent, mo偶emy sprawdzi膰 czy jest zaimplementowany jako nsISOund,a je艣li tak, mo偶emy odegra膰 przez niego d藕wi臋k.

Proces wywo艂ywania XPCOM ze skrypt贸w jest nazywany XPConnect, kt贸ry jest warstw膮 t艂umacz膮c膮 obiekty skryptowe na obiekty wewn臋trzne.

Tworzenie obiekt贸w XPCOM

Mamy trzy kroki dla wywo艂ania komponentu XPCOM

  1. Pobranie komponentu.
  2. Pobranie cz臋艣ci komponentu, kt贸ra implementuje interfejs, jaki chcemy u偶y膰.
  3. Wywo艂anie potrzebnej nam funkcji.

Kiedy wykonasz pierwsze dwa kroki, mo偶esz powtarza膰 ostatni krok tak cz臋sto jak to konieczne. Powiedzmy, 偶e chcesz zmieni膰 nazw臋 pliku. Mo偶emy u偶y膰 interfejsu nsILocalFile. Pierwszym krokiem jest pobranie komponentu plik. Drugim jest wykonanie zapytania do komponentu plik i pobranie jego cz臋艣ci ,kt贸ra implementuje interfejs nsILocalFile. W ko艅cu wywo艂ujemy funkcje dostarczone przez ten interfejs. Interfejs ten jest u偶yty do przedstawienia pojedynczego pliku.

Widzieli艣my ,偶e interfejsy s膮 zawsze nazywane zaczynaj膮c od 'nsI' Komponenty ,jednak, odwo艂uj膮 si臋 do stosowania sk艂adni URI. Mozilla przechowuje list臋 wszystkich komponent贸w, kt贸re s膮 dost臋pne w swoim w艂asnym rejestrze. Poszczeg贸lni u偶ytkownicy mog膮 instalowa膰 nowe komponenty je艣li ich potrzebuj膮. Dzia艂aj膮 one jako plug-iny.

Mozilla dostarcza komponentu plik, to znaczy komponent implementuj膮cy nsILocalFile. Do tego komponentu mo偶na odnie艣膰 si臋 u偶ywaj膮c URI '@mozilla.org/file/local;1' Komponent: Schemat URI jest u偶ywany do okre艣lenia komponentu, Do pozosta艂ych komponent贸w odnosimy si臋 w podobny spos贸b.

URI komponentu mo偶e by膰 u偶yte dla pobrania komponentu. Mo偶esz pobra膰 komponent u偶ywaj膮c kodu JavaScript podobnego do poni偶szego:

var aFile = Components.classes["@mozilla.org/file/local;1"].createInstance();

Komponent plik jest wyszukiwany i przechowywany w zmiennej aFile. Components w tym powy偶szym przyk艂adzie odnosi si臋 do obiektu og贸lnego, kt贸ry dostarcza pewnego komponentu pokrewnego funkcjom. Tutaj pobrali艣my klas臋 komponentu z w艂a艣ciwo艣ci classes. W艂asno艣膰 classes jest to tablica wszystkich dost臋pnych komponent贸w. Aby uzyska膰 inny komponent, zast膮p URI wewn膮trz nawias贸w kwadratowych na URI komponentu jakiego chcesz u偶y膰. Na ko艅cu jest egzemplarz funkcja createInstance

Powiniene艣 sprawdzi膰 warto艣膰 zwracan膮 z createInstanceaby upewni膰 si臋 ,偶e nie jest to warto艣膰 zerowa, kt贸ra wskazywa艂a by, 偶e komponent nie istnieje.

Jednak偶e, w tym miejscu, mamy tylko referencj臋 do samego komponentu plik. 呕eby wywo艂a膰 z niego funkcje potrzebujemy pobra膰 jeden z jego interfejs贸w, w tym przypadku nsILocalFile. Druga linia jak膮 potrzeba doda膰 jest nast臋puj膮ca:

var aFile = Components.classes["@mozilla.org/file/local;1"].createInstance();
if (aFile) aFile.QueryInterface(Components.interfaces.nsILocalFile);


Funkcja QueryInterface jest funkcj膮 dostarczan膮 przez wszystkie komponenty, kt贸re mog膮 u偶yte do pobrania okre艣lonego interfejsu tego komponentu. Funkcja ta pobiera jedne parametr, interfejs jaki chcesz uzyska膰. W艂a艣ciwo艣膰 interfaces obiektu Components zawiera list臋 wszystkich tych interfejs贸w, kt贸re s膮 dost臋pne. Tu u偶ywamy interfejsu nsiLocalFile i przekazujemy go jako parametr do QueryInterface. Wynik jest taki ,偶e aFile b臋dzie si臋 odnosi艂 do tej cz臋艣ci komponentu, kt贸ry implementuje interfejs nsiLocalFile.

Te dwie powy偶sze linie JavaScript mog膮 by膰 u偶yte do pobrania dowolnego interfejsu dowolnego komponentu. Wystarczy zast膮pi膰 nazw臋 komponentu nazw膮 tego komponentu jakiego chcemy u偶y膰 i zmieni膰 nazw臋 interfejsu. Mo偶esz oczywi艣cie r贸wnie偶 u偶y膰 dowolnej nazwy zmiennej. Na przyk艂ad aby pobra膰 interfejs sound, mo偶esz zrobi膰 co艣 takiego:

var sound = Components.classes["@mozilla.org/sound;1"].createInstance();
if (sound) sound.QueryInterface(Components.interfaces.nsISound);

Interfejsy XPCOM mog膮 dziedziczy膰 z innych interfejs贸w. Interfejsy kt贸re dziedzicz膮 z innych maj膮 swoje w艂asne funkcje i funkcje wszystkich tych interfejs贸w z kt贸rych dziedzicz膮. Wszystkie interfejsy dziedzicz膮 z interfejsu najwy偶szego poziomu nazwanego nsISupport. Ma on jedn膮 funkcj臋 dostosowan膮 do JavaScript, QueryInterface, kt贸r膮 ju偶 widzieli艣my. Poniewa偶 interfejs nsISupport zaimplementowa艂y wszystkie komponenty, funkcja QueryInterface jest dost臋pna w ka偶dym komponencie.

Kilka komponent贸w mo偶e zaimplementowa膰 ten sam interfejs. Zazwyczaj, mog膮 by膰 podklasami orygina艂u ale nie koniecznie. Dowolny komponent mo偶e zaimplementowa膰 funkcjonalno艣膰 nsILocalFile. Dodatkowo komponent mo偶e zaimplementowa膰 kilka interfejs贸w. Jest tak z powodu tego, 偶e dwa kroki s膮 wymagane w celu uzyskania interfejsu wywo艂uj膮cego funkcje.

Jednak偶e jest skr贸t jakiego mo偶emy u偶y膰 poniewa偶 cz臋sto b臋dziemy stosowa膰 te linie razem:

var aLocalFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);

Wykonuje to t膮 sam膮 rzecz jak dwie linie ale w jednej linii kodu. Eliminuje to potrzeb臋 tworzenia egzemplarza a potem zapytania go o interfejs w dw贸ch oddzielnych krokach.

Je艣li wywo艂ujesz QueryInterface w obiekcie a 偶膮dany interfejs nie jest obs艂ugiwany przez ten obiekt, pojawi si臋 wyj膮tek. Je艣li nie jeste艣 pewny czy interfejs jest obs艂ugiwany przez komponent mo偶esz u偶y膰 do sprawdzenia tego operatora instanceof:

var aFile = Components.classes["@mozilla.org/file/local;1"].createInstance();
if (aFile instanceof Components.interfaces.nsILocalFile){
  // do something
}

Operator instanceof zwraca prawd臋 je艣li aFile implementuje interfejs nsILocalFile. Wywo艂ywanie QueryInterface ma r贸wnie偶 efekt uboczny, w ten spos贸b aFile b臋dzie potem wa偶nym nsiLocalFile.

Wywo艂ywanie funkcji z interfejsu

Teraz kiedy mamy obiekt, kt贸ry odnosi si臋 do komponentu z interfejsem nsiLocalFile, mo偶emy wywo艂a膰 przez niego wywo艂a膰 funkcje nsiLocalFile. Poni偶sza tabela pokazuje kilka z w艂a艣ciwo艣ci i metod interfejsu nsiLocalFile.

initWithPath聽
Ta metoda jest u偶ywana do zainicjalizowania 艣cie偶ki dost臋pu i nazwy pliku dla nsiLocalFile. Pierwszy parametr powinien by膰 艣cie偶k膮 do pliku np: '/usr/local/mozilla'.
leafName聽
Nazwa pliku bez cz臋艣ci z katalogiem.
fileSize聽
Nazwa pliku bez cz臋艣ci z katalogiem.
isDirectory()聽
Zwraca prawd臋 je艣li nsiLocalFile przedstawia katalog.
remove(recursive)聽
Usuwa plik. Je艣li parametr recursive to prawda, katalog i wszystkie jego pliki i podkatalogi r贸wnie偶 b臋d膮 usuni臋te.
copyTo(directory,newname)聽
Kopiuje plik do innego katalogu, opcjonalnie zmieniaj膮c nazw臋 pliku. Ten katalog powinien by膰 nsILOcalFile mieszcz膮cym katalog dla kopiowanego pliku.
moveTo(directory,newname)聽
Przenosi plik do innego katalogu, lub zmienia nazw臋 pliku. Katalog powinien by膰 nsILocalFile mieszcz膮cym katalog dla przenoszonego pliku.

Aby usun膮膰 plik najpierw musimy przypisa膰 plik do nsiLOcalFile. Mo偶emy wywo艂a膰 metod臋 initWithPath wskazuj膮c膮, jaki plik mamy na my艣li. Potem przypisujemy 艣cie偶k臋 pliku do tej w艂a艣ciwo艣ci. Nast臋pnie wywo艂ujemy funkcj臋 remove. Pobiera ona jeden parametr kt贸ry wskazuje czy usuwanie jest rekurencyjne. Poni偶szy kod demonstruje te dwa kroki:

var aFile = Components.classes["@mozilla.org/file/local;1"].createInstance();
if (aFile instanceof Components.interfaces.nsILocalFile){
  aFile.initWithPath("/mozilla/testfile.txt");
  aFile.remove(false);
}

Ten kod pobiera plik /mozilla/testfile.txt i usuwa go. Wypr贸buj ten przyk艂ad przez dodanie tego kodu do programu obs艂ugi zdarze艅. Powiniene艣 zmieni膰 nazw臋 istniej膮cego pliku jaki chcia艂 by膰 usun膮膰.

W powy偶szej tablicy funkcji, zobaczysz dwie funkcje copyTo i moveTo. Te dwie funkcje mog膮 by膰 u偶yte, odpowiednio, do skopiowania plik贸w i przeniesienia plik贸w. Zauwa偶 ,偶e nie pobieraj膮 one parametru ci膮gu dla katalogu do kt贸rego kopiujemy lub usuwamy, ale zamiast tego pobieraj膮 nsILocalFile. Oznacza to ,偶e musisz pobra膰 dwa komponenty plik. Poni偶szy przyk艂ad pokazuje jak skopiowac plik.

function copyFile(sourcefile,destdir)
{
  // get a component for the file to copy
  var aFile = Components.classes["@mozilla.org/file/local;1"]
    .createInstance(Components.interfaces.nsILocalFile);
  if (!aFile) return false;

  // get a component for the directory to copy to
  var aDir = Components.classes["@mozilla.org/file/local;1"]
    .createInstance(Components.interfaces.nsILocalFile);
  if (!aDir) return false;

  // next, assign URLs to the file components
  aFile.initWithPath(sourcefile);
  aDir.initWithPath(destdir);

  // finally, copy the file, without renaming it
  aFile.copyTo(aDir,null);
}

copyFile("/mozilla/testfile.txt","/etc");

Us艂ugi XPCOM

Niekt贸re komponenty XPCOM s膮 specjalnymi komponentami nazwanymi us艂ugami. Nie stworzysz ich egzemplarzy poniewa偶 istnieje tylko jeden. Us艂ugi dostarczaj膮 funkcji og贸lnych, kt贸re albo pobieraj膮 albo ustawiaj膮 dane globalne lub wykonuj膮 dzia艂ania na innych obiektach. Zamiast wywo艂ania createInstance, wywo艂ujesz getService dla pobrania referencji do komponentu us艂ugi. Us艂ugi nie r贸偶ni膮 si臋 bardzo od innych komponent贸w.

Jedn膮 z takich dostarczonych us艂ug z Mozill膮 jest us艂uga zak艂adek. Pozwala ona dodawa膰 zak艂adki do bie偶膮cej listy zak艂adek u偶ytkownika. Przyk艂ad jest pokazany poni偶ej:

var bmarks = Components.classes["@mozilla.org/browser/bookmarks-service;1"].getService();
bmarks.QueryInterface(Components.interfaces.nsIBookmarksService);
bmarks.addBookmarkImmediately("http://www.mozilla.org","Mozilla",0,null);

Najpierw jest wyszukiwany komponent"@mozilla.org/browser/bookmarks-service;1" a jego us艂uga jest umieszczona w zmiennej bmarks. U偶yjemy QueryInterface dla pobrania interfejsu nsIBookmarksService. Funkcja addBookmarkImmediately dostarczana przez ten interfejs mo偶e by膰 u偶ywana dla dodawania zak艂adek .Pierwsze dwa parametry tej funkcji s膮 URL'ami zak艂adek i ich tytu艂ami. Trzeci parametr jest typem zak艂adki, kt贸rym zazwyczaj b臋dzie 0,a ostatni parametr jest typem kodowania znak贸w dokumentu b臋d膮cego dodawanym do zak艂adek, kt贸ry mo偶e by膰 zerem.

Nast臋pnie zobaczymy niekt贸re z interfejs贸w dostarczanych z Mozill膮, jakie mo偶emy zastosowa膰.