-
Apr 17th, 2024, 01:40 AM
#1
Thread Starter
Hyperactive Member
Confusion about Interfaces
Hi all.
I have a couple of questions regarding Interfaces.
1- Say we have two classes that both implement a common interface. For example:
StdPicture Class implements IPersistStream
Stream Class implements IPersistStream
My understanding is that, in theory, each implementation of IPersistStream need not be the same. ie: StdPicture and Stream classes should have the liberty to execute diff codes for any given IPersistStream function.
But in practice, that's not what I see. It wouldn't make sense for each Class to execute a diff code for a common interface function. It would yield chaotic and unexpected results.
2- Another thing I am confused about is that an Interface contains only the skeleton definitions of functions and no code as opposed to implementations of the interface. However, I see that some Interfaces implement other interfaces meaning they do contain code (implementation code of the other interface(s)) not just function signatures.
Thanks.
Last edited by AngelV; Apr 17th, 2024 at 01:47 AM.
-
Apr 17th, 2024, 02:10 AM
#2
Re: Confusion about Interfaces
1) That mess is part of why VB6/VBA don't allow you to use Implements on interfaces that inherit from anything besides IDispatch or IUnknown, and it handles those two under the hood. In twinBASIC (and obviously C/C++), you can, but you have control over whether you write separate or common implementations, and you're right, you *should* use a common one, but don't *have to*.
2) I'm not sure what you mean here; interfaces don't implement other interfaces. They can inherit from them, but that just means the function pointers of the inherited interface precede its own in the vtable.
Last edited by fafalone; Apr 17th, 2024 at 02:16 AM.
-
Apr 17th, 2024, 02:12 AM
#3
Re: Confusion about Interfaces
@1
On the Contrary: I'd expect different behaviour
You define an Interface "IAnimal" which provides a Skeleton-Procedure "Move"
You define three classes "Dog", "Snake" and "Fish" which each implement IAnimal.
You write the different code for each "Move"-Procedure for your 3 classes
Now if you pass one of the 3 "Classes" to a Function which expects an IAnimal-Object as an Argument, that Procedure will automatically know WHICH code to execute
Code:
Public Function SomeFunction(ByRef SomeAnimal As IAnimal) As SomeType
SomeAnimal.Move
End Function
@2
If you have a "Chain" of Interfaces, any code contained within is ignored by the implementing object
But might be wrong, but that's my understanding of it
Last edited by Zvoni; Tomorrow at 31:69 PM.
----------------------------------------------------------------------------------------
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------------------
People call me crazy because i'm jumping out of perfectly fine airplanes.
---------------------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad
-
Apr 17th, 2024, 02:35 AM
#4
Thread Starter
Hyperactive Member
Re: Confusion about Interfaces
@fafalone:
Stdole.IPicture inherits from IUnknown but still, the following doesn't seem to work !
Code:
Implements stdole.IPicture
The above line when added to a class module compiles ok but the IDE doesn't show any of the IPicture Properties or Methods implementation handlers as one would expect. I wonder why that is.
I'm not sure what you mean here; interfaces don't implement other interfaces. They can inherit from them, but that just means the function prototypes of the inherited interface precede its own in the vtable
Yep. That's what I meant to say. Makes sense.
-
Apr 17th, 2024, 02:43 AM
#5
Thread Starter
Hyperactive Member
Re: Confusion about Interfaces
@Zvoni
On the Contrary: I'd expect different behaviour
Makes perfect sense with custom made interfaces but I still don't see how that would make sense with interfaces such as the one I mentioned (IPersistStream) when diff client classes such as Stream and StdPicture want to implement any of the IPersistStream Properties & Methods.
If you have a "Chain" of Interfaces, any code contained within is ignored by the implementing object.
But might be wrong, but that's my understanding of it
I think fafalone answered that.one.
-
Apr 17th, 2024, 03:48 AM
#6
Re: Confusion about Interfaces
 Originally Posted by AngelV
I still don't see how that would make sense with interfaces such as the one I mentioned (IPersistStream) when diff client classes such as Stream and StdPicture want to implement any of the IPersistStream Properties & Methods.
The difference is what each class does internally when the Interface method is called.
Take an StdPicture object that implements IPersistStream.
You can call the Save() method on it and the StdPicture object "saves" itself down the stream.
Question: What Data passes down that stream?
Answer: Whatever data the StdPicture needs to send to persist itself.
Same with the Load() method.
What Data will the StdPicture object expect to pull from the stream? Again, whatever it needs to populate itself.
Regards, Phill W.
-
Apr 17th, 2024, 04:34 AM
#7
Re: Confusion about Interfaces
 Originally Posted by AngelV
My understanding is that, in theory, each implementation of IPersistStream need not be the same. ie: StdPicture and Stream classes should have the liberty to execute diff codes for any given IPersistStream function.
But in practice, that's not what I see. It wouldn't make sense for each Class to execute a diff code for a common interface function. It would yield chaotic and unexpected results.
WAT? Of course the code is different with each implementation of IPersistStream.
This is like having Move method on a Form, FlexGrid and Image control and insisting that the code executed on Move is the same in all 3 objects.
Now, every form executes the same code on Move. When you move two Image controls it is the same Move method (the same code) which gets executed on both of them. But Move on form and Move on Image control execute different code.
cheers,
</wqw>
-
Apr 17th, 2024, 04:56 AM
#8
Re: Confusion about Interfaces
 Originally Posted by wqweto
WAT? Of course the code is different with each implementation of IPersistStream.
This is like having Move method on a Form, FlexGrid and Image control and insisting that the code executed on Move is the same in all 3 objects.
Now, every form executes the same code on Move. When you move two Image controls it is the same Move method (the same code) which gets executed on both of them. But Move on form and Move on Image control execute different code.
cheers,
</wqw>
I'll add to this, since i come from Lazarus/Freepascal:
Lazarus/FreePascal has your usual Controls you can place on a Form (TButton, TEdit, TLabel etc.), and they all inherit from a common "ancestor"-Interface, getting their Methods, e.g. the "Paint"-Method
BUT: In Lazarus you write code on a Windows-Machine, but then you decide to compile for Linux-GTK2 (or QT).
You don't have to change a single line in YOUR code, but in the background the Interface calls the correct method for the correct OS
This is just an example of why it's perfectly legal, that a common interface provides the possibility to execute different code
Last edited by Zvoni; Tomorrow at 31:69 PM.
----------------------------------------------------------------------------------------
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------------------
People call me crazy because i'm jumping out of perfectly fine airplanes.
---------------------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad
-
Apr 17th, 2024, 05:00 AM
#9
Thread Starter
Hyperactive Member
Re: Confusion about Interfaces
Thanks guys. I am happy that I have now this confirmed. Each implementing class executes *similar* but diff code under the hoods. (which is in fact, the whole point for bothering to have interfaces)
One more related question:
Why Implements stdole.IPicture added to a class module doesn't work like when implementing my own interfaces defined in my vbproject? Same with other interfaces from other referenced libraries.
-
Apr 17th, 2024, 05:35 AM
#10
Re: Confusion about Interfaces
 Originally Posted by AngelV
Why Implements stdole.IPicture added to a class module doesn't work like when implementing my own interfaces defined in my vbproject? Same with other interfaces from other referenced libraries.
Limitation of VBx -- it needs implemented interface to derive from IDispatch because VBx can produce dual-interfaces only (i.e. IDispatch based ones) and cannot produce non-dual interface (i.e. not derived from IDispatch) as would be the case if it allowed IPicture to be implemented.
VBx needs all it's classes to be "castable" to Object data-time (an IDispatch in disguise) so that Dim o As Object variable can hold a reference to an instance of any VBx class.
Btw, TwinBasic can implement stdole.IPicture (and stdole.IPictureDisp)
cheers,
</wqw>
-
Apr 17th, 2024, 05:41 AM
#11
Re: Confusion about Interfaces
 Originally Posted by AngelV
Thanks guys. I am happy that I have now this confirmed. Each implementing class executes *similar* but diff code under the hoods. (which is in fact, the whole point for bothering to have interfaces)
One more related question:
Why Implements stdole.IPicture added to a class module doesn't work like when implementing my own interfaces defined in my vbproject? Same with other interfaces from other referenced libraries.
Because there is no IPicture-Interface?
https://learn.microsoft.com/en-us/do...dole.ifontdisp
Last edited by Zvoni; Tomorrow at 31:69 PM.
----------------------------------------------------------------------------------------
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------------------
People call me crazy because i'm jumping out of perfectly fine airplanes.
---------------------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad
-
Apr 17th, 2024, 06:37 AM
#12
Re: Confusion about Interfaces
There is an IPicture interface but it's hidden and like the other interfaces in stdole2.tlb, VB6 restricts what you can do with it.
Here it wouldn't matter anyway-- the default definition of IPicture includes a method with an As Any argument and out-only arguents, which are unsupported by VB6 so you couldn't implement the interface as-is anyway. You'd need to make a typelib with a unrestricted, VB friendly version, like oleexp does with IUnknown and IDispatch..
-
Apr 17th, 2024, 06:53 AM
#13
Re: Confusion about Interfaces
Yes, having As Any parameters would be the true root cause.
There is no problem implementing IUnknown derived interfaces, just tested with oleexp.IContextMenu.
Casting such VBx implemented IContextMenu to Object succeeds because the default interface is always IDispatch derived so you get IDispatch on the default interface instead.
cheers,
</wqw>
-
Apr 17th, 2024, 07:32 AM
#14
Thread Starter
Hyperactive Member
-
Apr 17th, 2024, 08:00 AM
#15
Re: Confusion about Interfaces
How do you inspect default interface on a coclass with Object Viewer?
Here is a snippet from OLE View decompiled stdole2.tlb
Code:
typedef [public] Picture IPictureDisp;
[
uuid(0BE35204-8F91-11CE-9DE3-00AA004BB851)
]
coclass StdPicture {
[default] dispinterface Picture;
interface IPicture;
};
The default interface is actually Picture dispinterface. It is a dispinterface so all calls on StdPictures in VBx are late-bound.
In addition IPictureDisp turns out is a typedef (alias) of this Picture dispinterface.
cheers,
</wqw>
-
Apr 17th, 2024, 08:53 AM
#16
Thread Starter
Hyperactive Member
Re: Confusion about Interfaces
@wqweto
How do you inspect default interface on a coclass with Object Viewer?
No. I used TypeLib Browser by Jose Roca.
I now see I made a mistake as the default interface is not IPicture 78F80981 VS 78F80980 and I didn't see either where it clearly says at the bottom Picture (default interface) (See image attachements below)
It is a dispinterface so all calls on StdPictures in VBx are late-bound.
I see.
Is that the reason why both codes below work whether we use the New keyword or not ?
Code:
Dim oStdPic As New StdPicture
Set oStdPic = LoadPicture( ....
Code:
Dim oStdPic As StdPicture
Set oStdPic = LoadPicture( ....
-
Apr 17th, 2024, 10:09 AM
#17
Re: Confusion about Interfaces
Yes, As New declarations can happen with coclasses only (i.e. cannot use interface names).
For instance these 3 are equivalent:
Code:
Dim oStdPic As StdPicture
Set oStdPic = LoadPicture()
Debug.Print oStdPic.Handle
Dim oStdPic2 As Picture
Set oStdPic2 = LoadPicture()
Debug.Print oStdPic2.Handle
Dim oStdPic3 As IPictureDisp
Set oStdPic3 = LoadPicture()
Debug.Print oStdPic3.Handle
i.e. the 3 refs have the same properties/methods *but* only StdPicture is a coclass and can be used with As New.
The rule is simple: Dim with interface, New with coclass.
When you Dim with coclass (which everyone usually does) the compiler substitutes the coclass for its default interface.
As New "shortcut" syntax is the weird one as it has to both Dim and New so it's only possible with coclass which Dims with its default interface.
As New is frowned upon in professional code as the performance penalty is generally unacceptable (in most cases).
We are using As New shortcut only if the reference is going to be used for a single method call. For instance Dim oFrm As New MyForm : If oFrm.ShowForm(...) Then ... sole usage of the variable.
cheers,
</wqw>
-
Apr 17th, 2024, 10:45 PM
#18
Thread Starter
Hyperactive Member
Re: Confusion about Interfaces
The rule is simple: Dim with interface, New with coclass.
Makes sense as every vb* programmer knows and does work with CoClasses and Interfaces belonging to the StdOle libray as we have seen so far.
However, applying exactly the same logic to the MS excel library doesn't seem to work .
Code:
Dim oWB As Excel.Workbook
Set oWB = New Excel.Workbook '<== Error : Class not registered
Code:
Dim oWS As Excel.Worksheet
Set oWS = New Excel.Worksheet '<== Error : Class doesn't support automation or doesn't support expected inteface.
Despite Workbook and Worksheet, both being creatable CoClasses and both having Dual Default interfaces inheriting from IDispatch as shown in the attached images below.
This seems to clash with the above mentioned rule. So what's going on then?

Last edited by AngelV; Apr 17th, 2024 at 10:50 PM.
-
Apr 18th, 2024, 05:12 AM
#19
Re: Confusion about Interfaces
Try CreateObject("Excel.Workbook") instead of New.
-
Apr 18th, 2024, 07:55 AM
#20
Re: Confusion about Interfaces
 Originally Posted by AngelV
Makes sense as every vb* programmer knows and does work with CoClasses and Interfaces belonging to the StdOle libray as we have seen so far.
However, applying exactly the same logic to the MS excel library doesn't seem to work .
Code:
Dim oWB As Excel.Workbook
Set oWB = New Excel.Workbook '<== Error : Class not registered
Code:
Dim oWS As Excel.Worksheet
Set oWS = New Excel.Worksheet '<== Error : Class doesn't support automation or doesn't support expected inteface.
Despite Workbook and Worksheet, both being creatable CoClasses and both having Dual Default interfaces inheriting from IDispatch as shown in the attached images below.
This seems to clash with the above mentioned rule. So what's going on then?
Something is very wrong with Office typelibs in general. The above "rule" is how the language is designed to work.
My test:
Code:
Option Explicit
Sub Test()
Debug.Print TypeName(New Excel.Application)
Debug.Print CreateObject("Excel.Application").Version
Debug.Print TypeName(New Excel.Chart)
Debug.Print TypeName(CreateObject("Excel.Chart"))
Debug.Print TypeName(New Excel.OLEObject)
Debug.Print TypeName(CreateObject("Excel.OLEObject"))
Debug.Print TypeName(New Excel.QueryTable)
Debug.Print TypeName(CreateObject("Excel.QueryTable"))
Debug.Print TypeName(New Excel.Workbook)
Debug.Print TypeName(CreateObject("Excel.Workbook"))
Debug.Print TypeName(New Excel.Worksheet)
Debug.Print TypeName(CreateObject("Excel.Worksheet"))
End Sub
First line on my machine says "Error in loading DLL" but this doesn't contradict the rule.
Second line prints "15.0" so there is Excel.Application somewhere installed.
Btw, I never said "New with coclass" will always succeed. It's more about "New with interface" cannot even compile :-))
Btw, CreateObject with Workbook/Worksheet fails here too.
cheers,
</wqw>
-
Apr 18th, 2024, 11:05 PM
#21
Thread Starter
Hyperactive Member
Re: Confusion about Interfaces
Code:
Debug.Print TypeName(CreateObject("Excel.Worksheet"))
doesn't work (error : ActiveX component can't create object)
But the following works, although it yields Workbook instead of Worksheet !
Code:
Debug.Print TypeName(CreateObject("Excel.Sheet"))
-
Apr 19th, 2024, 04:04 AM
#22
Re: Confusion about Interfaces
 Originally Posted by AngelV
Code:
Debug.Print TypeName(CreateObject("Excel.Worksheet"))
doesn't work (error : ActiveX component can't create object)
But the following works, although it yields Workbook instead of Worksheet !
Code:
Debug.Print TypeName(CreateObject("Excel.Sheet"))
Office is bonkers!
Cannot imagine what one can do with such "detached" worksheet.
cheers,
</wqw>
Last edited by wqweto; Apr 19th, 2024 at 10:39 AM.
-
Apr 19th, 2024, 10:34 AM
#23
Thread Starter
Hyperactive Member
Re: Confusion about Interfaces
Thanks a lot guys. I have learnt so much from you
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|