Closed fafalone closed 2 years ago
I am in favour of this proposal.
What do you suggest, syntax-wise, for events? I don't find the term "Source" interface very BASIC-friendly, but then neither is "Coclass", so I'm not overly concerned, especially since this feature is not really intended for the average BASIC user.
We also need to consider that we don't yet support defining dispinterfaces directly in tB either. Ideally we should expand this request to cover them as well. They should be easy, since it could perhaps just be a [ DispInterface ]
attribute on the interface.
Just as a clarification, how would that be implemented?
Coclass technically is an abstract description that amounts to saying "there's an implementation that supports so and so interfaces, and BTW so and so can be used as source interface(s), and it might have a default non-source interface and a default source interface".
Therefore, the proposal would be basically a different kind of Interface
that can be applied on a Class
which would then mandate that this class implements all the interfaces described in the CoClass
.
The alternative is just to define a ClassId
attribute on the Class
(which we already have) and define the interfaces implemented on that Class
which would indirectly define the coclass. It must do this anyway in order to generate a valid type library where an instance can be gotten or created via the appropriate class factory. The problem with the indirect approach, however, is that it ignores the fact that a coclass implementation need not actually correspond to a single class implementation nor should the class implementation be restricted to a single coclass definition. Still, because it's required to create the coclass for such class without an explicit implementation, it might be good to be clear whether there should be restrictions such as disallowing a class implementation to have both a ClassId
attribute and implement a coclass, or whether it would mean that it implements two coclasses. I think the latter would be quite confusing. Thus the question of how coclass
should co-exist with the ClassId
attribute should be clarified, I think.
RE: the terminology question -- I agree that "Source" isn't very intuitive but we also need to consider minimizing the cognitive load from translating between the IDL versus consistency with VB language syntax. I might be mistaken but I seem to remember that there are cases where source interfaces can be used without using events which may be one of the reasons why they weren't called "event interface". If that is the case, and we are shooting for compatibility with IDL, then conforming to IDL's syntax might be more appropriate. That will be particularly true if we choose to import MIDL attributes as attributes in the tB language.
The only place I've ever even seen 'source' as an attribute is in stdole2.tlb... haven't encountered using that, or dispinterfaces, anywhere besides VB's picture and font stuff (except a single dispinterface in the shell32 automation typelib I've never actually used, DShellFolderViewEvents).
I'd agree with bclothier on the terminology question; I don't think the situation would be helped by trying to come up with something better than the existing IDL keywords; this is a fairly narrow area that I don't think is of much interest except to those already using IDL; I'm not sure any marginal improvement in clarity would outweigh having to learn a bunch of differences from the existing setup.
As far as events syntax; aren't we pretty much constrained to have them as regular methods, as that's how it's done in VB?
I have to admit I hadn't thought about the from the perspective of a coclass for an implementation within tB... I've only ever used these as a consumer of default implementations provided by Windows; so I'd have to defer to the more knowledgeable about how that actually works behind the scenes for the best way to proceed for a coclass provider rather than consumer.
It comes down to this;
CoClass
says: there's this class available that I can instantiate via the COM registry that supports such and such interfaces.
Class
says: there's this class available, that I can instantiate internally (since I am implementing it) that supports such and such interfaces.
It's true that we generate CoClass
entries in a generated type library for COM-exposed classes when we build an ActiveX DLL, but other than that I propose no further overlap to prevent muddying the waters. The CoClass
support suggested here is purely to avoid having to include a type library in order to declare existing CoClass
entries.
@fafalone If you look at something like one of the Office apps type libraries (e.g. Access, Excel) you will see source interfaces in coclasses, and dispinterfaces, used extensively. In your particular use case, I can understand them not being used much.
Btw, can TB currently Implement
both default interface and source dispinterface of a coclass somehow in a single class?
The idea is to produce a carbon copy of a coclass (with different CLSID), something which is not possible in VBx
Btw, can TB currently
Implement
both default interface and source dispinterface of a coclass somehow in a single class?
It is partially implemented, and used internally in the WinNativeForms package. The provisional syntax is just Events IFooEvents
statement inside a class, however at the moment IFooEvents must be defined inside the project, and so this limits its use (particularly as we can't yet define dispinterfaces).
Additionally, I just checked and RaiseEvent
isn't yet working with it. So whilst the Events IFooEvents
statement brings over the events and exposes them on the class correctly, this feature is not quite ready for prime time yet.
One more point.... wouldn't we need the option to provide a custom implementation of the IClassFactory
/IClassFactory2
? Normally we don't have to because tB will handle that internally for us, but that would be necessary if we were to implement a OOP COM server or implement custom logic (e.g. a mutex for singleton, a la Outlook.Application
). I mention this because that could be a provided as an extension to the CoClass
syntax (e.g. as an event, similar to the Initialize
event, perhaps).
This is now supported, as of BETA 166. The CoClass
component type allows for the self-explanatory attributes of [CoClassId("")]
, [PredeclaredId]
, [AppObject]
, [Restricted]
and [COMCreatable]
. The attributes [Default]
and [Source]
are allowed on the Interface
entries. You must define one interface as [Default]
.
Here is an example:
[ CoClassId ("0BE35203-8F91-11CE-9DE3-00AA004BB851") ]
[ COMCreatable ]
CoClass StdFontCustom
[ Default ] Interface stdole.Font
[ Default, Source ] Interface stdole.FontEvents
Interface stdole.IFont
End CoClass
In addition, and related to the question immediately above from @bclothier, there is another attribute of interest:
[CoClassCustomConstructor("procName")]
. By default, the construction of CoClass
types is done through COM via CoCreateInstance
as you'd expect. If you want to override that behaviour, then you can provide the name of a custom constructor procedure here. We are now using this for the VB.Global
class, as can be seen in WinNativeForms package:
[ CoClassId ("FCFB3D23-A0FA-1068-A738-08002B3371B5") ]
[ CoClassCustomConstructor ("[_HiddenModule].CreateGlobalObject") ]
[ AppObject ]
Public CoClass Global
[ Default ] Interface VBGlobal
End CoClass
With the above definition, when the Global
class needs to be instantiated, the procedure [_HiddenModule].CreateGlobalObject
is called. This allows the compiler to provide the actual implementation of the coclass, rather than going through COM. I'm sure some of you will find uses for this feature. E.g:
[ CoClassId ("0BE35203-8F91-11CE-9DE3-00AA004BB851") ]
[ CoClassCustomConstructor ("COMStuff.CreateFontObject") ]
[ COMCreatable ]
CoClass StdFontCustom
[ Default ] Interface stdole.Font
[ Default, Source ] Interface stdole.FontEvents
Interface stdole.IFont
End CoClass
Module COMStuff
Public Function CreateFontObject(ByRef out As StdFont) As Long ' HRESULT
Debug.Print "StdFontCustom created..."
Set out = New StdFont
Const S_OK As Long = 0
Return S_OK
End Function
End Module
Forewarning: over time, the CoClassCustomConstructor
attribute might change, e.g. into a Sub New
inside the CoClass
syntax. For the time being, this attribute is available in this form.
tB really needs direct coclass support, since we have in-language support for interface definitions. These are supported as consumable from typelibs, so then just need the syntax then it's not a big leap to set them up.
I'd propose we could keep it similar to the translation of interface defs like this: