3

I am currently learning how to create Firefox addons using XPCOM and I want to know how to include thirdparty libraries to develop them. I followed a few tutorials to compile .xpt and .dll from c++ files (noted in: https://developer.mozilla.org/en/How_to_build_a_binary_XPCOM_component_using_Visual_Studio and http://nerdlife.net/building-a-c-xpcom-component-in-windows/) and I am not sure how we are suppose to include the files into an addon project (which gets packaged into .xpi file).

I am using Opencv (c++) to do image conversions via the addon such as resizing a very large image (3mb high res png) down to something small and simple (such as 600X800 200kb jpg) that will be done by my addon. I know that Opencv is written in c++ and xpcom can compile c++ code into a dll and xpt. I read a couple of tutorials but most of them points to adding these files (xpt and dll) in "C:/Program Files(x86)/Mozilla Firefox/components" instead of the addons "components/" folder (which is not how addons work, I believe). Though the Mozilla page (listed above) does include something about "{app}/components" and "{app}/application.ini" folders but I have never read anything like this, so therefore I am confused how this is done.

My other option is making the Opencv methods into an executable and then running it separately (similar to how MemoryFox addon runs an executable to clear Firefox's memory) and use that to conduct image resizing.

I am really not sure how to do this (I am new the addon development) and I would like to know how to accomplish this (using 3rd party C++ libs into the addons). An example, tutorial or explanation is fine to get me started.

Thanks in advance.

Edit: I would also like to inform that I have read threw most of https://developer.mozilla.org/en/Creating_XPCOM_Components (picked and choose topics) and it does not tell me how to achieve the above.

Wladimir Palant
  • 56,865
  • 12
  • 98
  • 126
user654628
  • 1,429
  • 1
  • 17
  • 37

2 Answers2

3

There are several places you can store an addon and inform FireFox of it's existence. Mostly it comes down to how you want to distribute it.

With MS Windows the loadLibrary process will search the current directory then the path. Simply locating your xpcom.dll alongside 3rdparty.dll in the components folder of your pluggin should work ok.

XPCOM is like windows COM but for across platforms.
Your designing to meet the requirements of interfaces.
Your addon may not need to define it's own interface (.idl -compiles-> .xpt, .h) but if it does from firefox 4 you will need to list this in the chrome.manifest.
Once compiled you will need to list your dll in the chrome.manifest also.

taking your example prototype function long Add(in long a, in long b);

baz_1.idl might look like

#include "nsISupports.idl" 
[scriptable, uuid(F0F0F0F0-AAAA-BBBB-CCCC-111111111111)]
interface iBaz : nsISupports
{ 
  long Add(in long a, in long b);
};

generate your header and xpi distrib

$(GECKOBIN_PATH)/xpidl -m header -I $(GECKOSDK_PATH)/idl -e baz_1.idl 
$(GECKOBIN_PATH)/xpidl -m typelib -I $(GECKOSDK_PATH)/idl -e baz_1.idl 

Link the contract guid to the contract name in C++ for FF4

NS_DEFINE_NAMED_CID(BAZ_CID); // defined in baz.h generated from baz_1.idl
static const mozilla::Module::ContractIDEntry kSLMozContracts[] = {
    { "@foo.bar.com/baz;1", &kBAZ_CID },
    { NULL }
};

usage in C++
nsCOMPtr<iBaz> baz = do_CreateInstance("@foo.bar.com/baz;1",&rv);

usage in JavaScript
var baz = components.classes["@foo.bar.com/baz"] .createInstance(Components.interfaces.iBaz);

Example.
We have a product that also provides a firefox addon, so we don't ship an xpi, but the addon sits in a subfolder of the product.

Product in
c:\program files\foo\

addon in - lets call this foobar
c:\program files\foo\bar

register the addon

HKLM\SOFTWARE\Mozilla\Firefox\Extensions\
"{GUID}"="c:\program files\foo\bar"

so then the layout of the addon is

foobar\chrome.manifest
foobar\install.rdf
foobar\components\baz_1.xpt
foobar\components\baz_1_32.dll
foobar\components\baz_1_64.dll
foobar\components\someOtherWorker.dll
foobar\chrome\ui.jar

In FF < 4 you didn't need to list binaries in the manifest, things in components folder are loaded and checked for functions to see if they are xpcom, so a chrome manifest might have looked like

content baz jar:chrome/ui.jar!/content/baz/
skin baz classic/1.0 jar:chrome/ui.jar!/skin/classic/baz/ 

From FF 4 the chrome manifest needs to list your binary files, so it then looks like (we only support 64 bit after FF 3.5)

content baz jar:chrome/ui.jar!/content/baz/
skin baz classic/1.0 jar:chrome/ui.jar!/skin/classic/baz/ 

interfaces components/baz_1.xpt
binary-component components/baz_1_32.dll ABI=WINNT_x86-msvc
binary-component components/baz_1_64.dll ABI=WINNT_x86_64-msvc appversion>=3.5

FireFox 5 (Out now) has changed

  • the formats of xpt files - so your interfaces won't be found by FF5 unless you build with that SDK.
  • the version of the xpcom registration - so FF5 won't use a dll built for FF4 as the xpcom version isn't high enough.
Greg Domjan
  • 13,943
  • 6
  • 43
  • 59
  • Thanks!! So using the tutorials I listed above, do they automatically compile the dll to 64 bit? Also I would like to know how to call the function via JavaScript (from the compiled dll). Interface: long Add(in long a, in long b); – user654628 Jun 25 '11 at 00:38
  • No auto compile to 64 bit. There is no windows supported 64 bit XulRunner SDK (yet), you need to build this yourself. Suggested site to help with this is http://wiki.mozilla-x86-64.com/Main_Page. Most installs of FF on 64 bit OS are still 32 bit to my knowledge. – Greg Domjan Jun 29 '11 at 17:55
2

The tutorial you refer to is about developing applications, not extensions. So application.ini doesn't apply in your case. Extensions have a manifest file called chrome.manifest, starting with Firefox 4 all XPCOM components and XPT files need to be registered there - or they will be ignored. It no longer matters where the component is located though components/ would still be the common place for them. https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0#Component_registration should be a good starting point - that should explain what you need to write there.

Note that the source code in the tutorials you were reading is outdated as well. Current code examples are linked to from https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0#Binary_components. And you should use XULRunner SDK 2.0 (corresponds to Firefox 4) or higher. Sorry, you arrived at a bad time - that's the biggest change to XPCOM in the past 10 years.

Wladimir Palant
  • 56,865
  • 12
  • 98
  • 126
  • Thanks!! How would you call the function from c++? Is it the same as if it was a JavaScript function? – user654628 Jun 25 '11 at 05:06
  • Once the XPCOM component is done you can use it just like a JavaScript XPCOM component - get a component instance and call methods on it. – Wladimir Palant Jun 25 '11 at 11:30
  • Thanks for the help. Now I got to compile for FF4 but I cannot get the instance to work correctly. `var instance = Components.classes['@example.com/MyComponent;1'].createInstance(); var obj = instance.QueryInterface(Components.interfaces.IMyComponent);` After this, it throws me an error: "Could not convert JavaScript argument arg 0 [nsISupports.QueryInterface]" nsresult: "0x80570009 (NS_ERROR_XPC_BAD_CONVERT_JS)". How do I fix this? – user654628 Jun 26 '11 at 03:23
  • @user654628: `Components.interfaces.IMyComponent` is undefined. Either you have a typo in the interface name or you forgot to register the XPT file. – Wladimir Palant Jun 26 '11 at 09:43
  • Yes, the XPCOM changes I linked to were introduced in Gecko 2.0 - that's Firefox 4. – Wladimir Palant Jun 26 '11 at 21:18
  • Yep i had my component listed after my interface, so i switched the order and it works. I tried to build a ff5 binary component but it doesnt work for ff3.6, is this normal? (Works for ff4 & 5) – user654628 Jun 26 '11 at 22:49
  • No, it should work if the component and the XPT file are in the `components/` subdirectory and you use the `NS_IMPL_MOZILLA192_NSGETMODULE` macro (Gecko 1.9.2 is Firefox 3.6). – Wladimir Palant Jun 27 '11 at 05:39
  • The main issue you would have is whether the interfaces you are using have changed between versions so when you do a query interface in C++ you can actually get the interface. – Greg Domjan Jun 27 '11 at 18:37
  • @Greg Domjan: That used to be the main issue - in Firefox 3.x. Now you have to recompile the component for each new major release, always :-( – Wladimir Palant Jun 27 '11 at 18:44
  • So it is suppose to work for all after compiling it for Firefox 5? `QueryInterface` doesn't work when running for 3.6 (code above) but I did include `NS_IMPL_MOZILLA192_NSGETMODULE` inside the module file (which is why when I compiled for FF4, it worked for FF4 and 3.6 however compiling for FF5, only FF5&4 worked but 3.6 didn't). – user654628 Jun 27 '11 at 21:40
  • I'm not sure why the same component works for Firefox 4 and 5 for you - `mozilla::Module::kVersion` is different for these Firefox versions (1 for the former, 2 for the latter). And that constant keeps changing, currently 6 for Firefox 6 and 7 for Firefox 7. So you should need to recompile your component with the correct version of XULRunner SDK for each major release after Firefox 4. Backwards compatibility with Firefox 3.x must work nevertheless, don't know why it doesn't for you. – Wladimir Palant Jun 28 '11 at 06:19
  • FF4 will load the module with kVersion 2 for some reason - it has more than enough info perhaps? where as FF5 won't load the dll for kVersion 1 - not enough info? – Greg Domjan Jun 29 '11 at 17:46
  • QueryInterface works off an ID, the ID should change when the interface does. The SDK only includes the latest interface. ie. 1.8 #define NS_IACCESSIBLEDOCUMENT_IID_STR "8781fc88-355f-4439-881f-6504a0a1ceb6" and 1.9 #define NS_IACCESSIBLEDOCUMENT_IID_STR "b7ae45bd-21e9-4ed5-a67e-86448b25d56b" You need to work out a way to resolve this or make multiple modules. – Greg Domjan Jun 29 '11 at 17:52