We help IT Professionals succeed at work.

How to raise interface events ?

dkjnkm
dkjnkm asked
on
Is to possible to raise events defined in a VB Interface class in their implementation class ? if so, how?
More details as follows -

Let's say there's a interface class module in VB as -

'------- begin ITest.cls ------------
public Event Result(Byval lResult& )
function AddNum( ByVal n1&, ByVal n2& ) as long
end function
'------- end --------------

and there are two class modules implementing Itest
cSample1
cSample2

and there's a controller cManager with code as follows -

private withEvents oTest as ITest
function doSomething( ByVal bTrue as boolean )
  if bTrue then
     set oTest = New cSample1
  else
     set oTest = New cSample2
  end if
end function
Private function ITest_Result(ByVal lResult as long)
   msgbox lResult
end function
------------------------
Comment
Watch Question

Commented:
Your event procedure in cManager should be called oTest_Result(byval lresult as long)

Commented:
Hello.
I'm sad to say...

You can not do this.
You can not implement Events.

The explanation why you can't is too complicated, but in short, they aren't supported.

Try using callback method or something...

Regards.

Author

Commented:
why is it not possible ? is there a workaround other than callbacks ? is it possible to do it in VC ? need some more reference info

zygwert - thanks for pointing out the typo! but that's not the answer i was looking for

Commented:
Here is why you have a problem:

Events are really interfaces that a CLASS is willing to make calls on.  Clients can manage the connections using the ConnectionPoint interfaces.  One way to discover information about the events a class will support is to look at its type libary; find the coclass definition and look for interfaces marked as [source].

When you say dim "with events" x as y,
what matters is what is y.
If y is a class (coclass to COM), then VB will read the type type library that defines y and find an interface marked [default, source]. Then X can implement this interface, and VB will use the ConnectionPoint interfaces to connect x and y.

If y is not a class, but is just an interface, then x doesn't know what event interface to implement, so you don't get any events.  Source interfaces are properties of classes, not interfaces.

Use the OLE/COM object viewer to get a better view of the interfaces VB implements for you.

ITest is really a class, not just an interface.  When you say CSample1 implements ITest, what you mean is CSample1 implements the default interface of ITest.  Information about other interfaces, like ITest's event interface, is lost.

Commented:
Alternatives:
Here is the IDL from a C implementation of your problem.  Notice that both coclasses have the same source interface.  So, a client of either can use ITest for outgoing calls and IMyEvent for incoming calls.

     interface ITest : IUnknown
     {
          HRESULT AddNum([in] long n1, [in] long n2, [out, retval] long* pResult)

     };
     interface IMyEvent : IUnknown
     {
          HRESULT Result([in] long lResult);
     };
     coclass Sample1
     {
          [default] interface ITest;
          [default, source] interface IMyEvent;
     };
     coclass Sample2
     {
          [default] interface ITest;
          [default, source] interface IMyEvent;
     };
Commented:
Hi again.
Here's a workaround, maybe it's not the best, but it's easy to understand:
----------------------------------
1. Define a class, that holds only Events, and procedures that raises these events, like:

{Class IEvents}
Public Event FirstEvent
Public Event SecondEvent

public sub FireFirstEvent()
   RaiseEvent FirstEvent
end sub

public sub FireSecondEvent()
   RaiseEvent SecondEvent
end sub

-----------------------------
2.Add this 'events' class to your ITest class as property (or function), like this:

{Class ITest}

private m_IEvents as IEvents

private sub Class_Initialize()
   set m_IEvents = new IEvents
end sub

Public property Get EventsHldr as IEvents
   set EventsHldr = m_IEvents
end property

-----------------------
3.To use WithEvents on other classes, that implement ITest class, use "Public/Private WithEvents X as IEvents"
and then set X to cSample.EventsHldr, like:

Private withevents X as IEvents
Set X = cSample.EventsHldr

Got it?

Commented:
What a clever solution Julian K!  It's simple and easy to implement.

I've been thinking about the case when the server object or interface is beyond your control, making an events property impossible.

The only way VB is willing to do events is when it knows the class name at compile time.  Since this is pretty restrictive, you could create a COM object which does events without bothering VB.  This is not as simple & easy to imlements -- unless someone has already done it and published it.

This connector object would take IUnknown* for the source, an IDispatch* for the sink, and a prefix string for the callback methods.  It would connect up to the source and when it gets an event from the source, it would make an IDispatch Invoke to the sink for a method named "Prefix_" & ActualMethodName.  You would get everything but intellisense.  Then your server objects could each raise events with the same method signature; VB will give the interfaces different IIDs, but everything will work because you are using IDispatch and you only care about the method name, not the DispID.

Commented:
To zygwert:
Yep, You're right. Your solution is more global, it needs some hard coding, though...
And I'm not too good using IUnknown/IDisplach interfaces - just cant' find good manual/book about how to use them.

Author

Commented:
excellent idea and simple to implement !

Explore More ContentExplore courses, solutions, and other research materials related to this topic.