digitalmars.D.learn - extern(Windows) on XPCOM
- Li Jie <cpunion gmail.com> Apr 12 2007
- Chris Nicholson-Sauls <ibisbasenji gmail.com> Apr 12 2007
- Li Jie <cpunion gmail.com> Apr 21 2007
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
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
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








Li Jie <cpunion gmail.com>