www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - extern(Windows) on XPCOM

reply Li Jie <cpunion gmail.com> writes:
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?
Apr 12 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
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. *ponder ponder* -- Chris Nicholson-Sauls
Apr 12 2007
parent Li Jie <cpunion gmail.com> writes:
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.
Apr 21 2007