extern(Windows) on XPCOM

Li Jie cpunion at gmail.com
Sat Apr 21 05:56:54 PDT 2007


Chris Nicholson-Sauls дµ½:

> 
> Li Jie wrote:
> > I want to call XPCOM and write XPCOM component with D, but I have some problems.
> > 
> > This is COM object virtual table structure:
> > # COM:
> > # vtbl -> | a_pointer (I don't know what is this)
> > #         | QueryInterface
> > # 	| AddRef
> > # 	| Release
> > 
> > And this is XPCOM object virtual table:
> > # XPCOM:
> > # vtbl -> | QueryInterface
> > # 	| AddRef
> > # 	| Release
> > 
> > extern(Windows) only compatible COM, because it added an offset, XPCOM do not need this.
> > When call QueryInterface, it really call AddRef.
> > And I tried extern(C++) and extern(Pascal), no changes.
> > 
> > I think that there are 4 solutions:
> > 
> > 1. Don't use interface, replace with struct, C style:
> > # struct nsISupportsVtable  
> > # {  
> > # extern(Windows) :  
> > #     nsresult function (nsISupports*, nsIID* uuid, void** result) QueryInterface;  
> > #       
> > #     nsrefcnt function(nsISupports*) AddRef;  
> > #       
> > #     nsrefcnt function(nsISupports*) Release;  
> > # }  
> > #   
> > # struct nsISupports  
> > # {  
> > #     nsISupportsVtable* vtbl;  
> > # }
> > 
> > Ugly! but it can works.
> > 
> > 
> > 2. Modify XPCOM interface, remove QueryInterface method:
> > # extern(Windows)  
> > # interface nsISupports  
> > # {  
> > #     // Remove it from D interface  
> > #     // nsresult QueryInterface(nsIID* uuid, void** result);  
> > #   
> > #     nsrefcnt AddRef();  
> > #   
> > #     nsrefcnt Release();  
> > # }  
> > #
> > # private  
> > # struct VTBL  
> > # {  
> > #     extern(Windows) nsresult function (nsISupports, nsIID*, void**) QueryInterface;  
> > # }  
> > #   
> > # private  
> > # struct ISupports  
> > # {  
> > #     VTBL* vtbl;  
> > # }  
> > #   
> > # nsresult MyQueryInterface(nsISupports obj, nsIID* iid, void** pout)  
> > # {  
> > #     ISupports* p = cast(ISupports*)cast(void*)obj;  
> > #     return p.vtbl.QueryInterface(obj, iid, pout);  
> > # } 
> > 
> > It can works, replace nsISupports.QueryInterface with MyQueryInterface. But I can't write XPCOM component with D, because no QueryInterface in interface.
> > 
> > 
> > 3. Hack DMD:
> > # int InterfaceDeclaration::vtblOffset()
> > # {
> > #     if (isCOMclass())
> > # 	return 0;
> > #     return 1;
> > # }
> > 
> > Change to:
> > 
> > # int InterfaceDeclaration::vtblOffset()
> > # {
> > #     return 0;
> > # }
> > 
> > And add pointer to IUnknown:
> > # extern(Windows)
> > # interface IUnknown
> > # {
> > #     void ___dont__call__me__please_______();
> > #     HRESULT QueryInterface(IID* riid, void** pvObject);
> > #     ULONG AddRef();
> > #     ULONG Release();
> > # }
> > 
> > I don't know whether it can work.
> > 
> > 4. Hack DMD, add extern(XPCOM), I think it's very difficult to do.
> > 
> > 
> > Any ideas?
> 
> I would think a merge of options 3. and 4. would be good.  Ie, add either a second 
> interface (IXPUnknown perhaps) or an extern(XPCOM), and modify DMD's 
> InterfaceDeclaration::vtblOffset to know about the special case.  It'd be Walter's choice, 
> and I'm not so sure XPCOM would be anywhere near the top of his priority list.

My friend, h_rain has found a simple way, rename nsISupports to IUnknown, like this:

---------------------------------------
extern(Windows)
interface IUnknown {
  // some methods
}

alias IUnknown nsISupports;

extern(Windows)
interface nsIFile : nsISupports {
  // some methods
}
---------------------------------------

It works fine, and it is beautiful.


More information about the Digitalmars-d-learn mailing list