I have an interface which inherits from another interface, like this:
[
object,
uuid(72A6E473-9956-4856-A335-B9169359AACE),
dual,
nonextensible,
pointer_default(unique)
]
interface IA : IDispatch
{
HRESULT MethodA();
}
[
object,
uuid(378846D3-7E24-4DAE-B4DF-69AA4B0C1AA9),
dual,
nonextensible,
pointer_default(unique)
]
interface IB : IA
{
HRESULT MethodB();
}
[
object,
uuid(4C187526-6809-4A57-A3ED-626E0B36F7DB),
dual,
nonextensible,
pointer_default(unique)
]
interface ICollection : IDispatch
{
HRESULT GetObject([out, retval] IA** ppValue);
}
The ICollection implementation will return an object which implements IB. That object will provide access to MethodA and MethodB via the dispatch interface. There will be no additional members added at run time.
Is the nonextensible attribute on IA allowed in this case?
Is the nonextensible attribute on IA allowed in this case?
Yes, it is.
The [nonextensible]
attribute of an interface, translated into the typelib type flag TYPEFLAG_FNONEXTENSIBLE
, has the practical effect of telling Visual Basic (6 or for Application) not to look for missing members with the underlying IDispatch
.
Dim A As IA
Set A = Obj ' QueryInterface
A.MethodA
' Compilation error
' A.MethodB
' If A.Property Then A.MethodC
Dim B As IB
Set B = Obj ' QueryInterface
B.MethodA
B.MethodB
' Compilation error
' If B.Property Then B.MethodC
Without [nonextensible]
, Visual Basic would compile the missing method calls and property accesses, if uncommented, as calls to IDispatch::GetIDsOfNames
followed by IDispatch::Invoke
.
Generally, this is a good thing if you favor compile-time checks, forcing the code to declare the variable as Object
or Variant
if it needs dynamic lookup. It might be a hassle on expando objects, but those violate one point of IDispatch
's contract anyway:
IDispatch::GetIDsOfNames method
…
Remarks
…
The member and parameter DISPIDs must remain constant for the lifetime of the object. This allows a client to obtain the DISPIDs once, and cache them for later use.
…
Caution You cannot use this method to access values that have been added dynamically, such as values added through JavaScript. Instead, use the GetDispID of the IDispatchEx interface. For more information, see the IDispatchEx interface.
…
EDIT: Here's a sample you can try with Word VBA (Alt+F11), add a macro and paste this text:
Dim Docs As Documents
Set Docs = Application.Documents
Docs.Add
' Compilation error
' Docs.Foo
Dim Doc As Document
Set Doc = Docs(0)
Doc.Activate
Doc.Foo
To try it out, select the menu Debug → Compile Project.
It should compile successfully. Although the (default) interface (for) Document
doesn't have a Foo
method, it's not [nonextensible]
(careful with the double negative), so the call is turned into runtime dispatching.
Now, uncomment Docs.Foo
and recompile the project.
It should throw an error, because the (default) interface (for) Documents
is [nonextensible]
and the call to the missing Foo
method is not turned into runtime dispatching.