callback function raising an event

What is the best way to have a callback function raise an event located in a class module?

Scenario:
I have a timer class that is bound to a callback function.  The callback function get's called within a timer interval specified.  As you all know the callback function has to be in a standard module and not a class module.

I want that callback function to raise an event inside the same timer class, how can I do this?

I don't want to use any forms, so that solution is not an option.
LVL 10
aeklundAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
AzraSoundConnect With a Mentor Commented:
I assumed you would be doing something to that effect.  There really is no way around it as the class module is dependent upon the call in the standard module.  You can still use interfaces as I indicated to make it appear somewhat seamless, but you must provide a way for the standard module to reference, at the very least, your timer class.  This may be well suited to compile as a DLL (your timer class and standard module).
0
 
AzraSoundCommented:
Well, as you know, you can not raise events from a standard module, so you are left with either having your module just "know" a function in your class it can call, or you can be more "technically correct" and have your class implement a particular interface that the standard module can then call a method of.
0
 
aeklundAuthor Commented:
I have Class "A" that references my Timer class.  It sets a timer with an interval of 60 seconds...  Now when 60 seconds it reached, it called a callback function in a standard module.  Now how can I get that callback function to reference the instance of Class "A" that set the timer?

I don't want to hard code any function names inside the timer class or the callback function.  This way I can use this timer class for multiple projects.
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
emadatCommented:
Refer to the article:
http://archive.devx.com/upload/free/features/vbpj/2000/02feb00/mc0200/mc0200.asp

If you can call the callback function with the AddressOf(your class specific function), then I think using the technique discussed in this article will help you.
0
 
FunkyMeisterCommented:
Setting your call back function you ue the AddressOf against an object.

Sub SetCallback(CallBack as Object)
CallbackAddress=AddressOf(CallBack)
...
End Sub

That way, you merely:

SetCallback Me.Thisfunction
0
 
AzraSoundCommented:
Unless you are using some API that expects a function pointer, the AddressOf suggestion probably won't do you any good because pointers to VB functions can't be passed within VB.

>>I don't want to hard code any function names inside the timer class or the callback function.  This way I can use this timer class for multiple projects.

Regardless, it sounds as if the timer class and the standard module work together.  The standard module needs to be able to reference your timer class in some way.  To allow this to work with any other class, provide an interface that any other class must implement, e.g.,


'class ITimerFriend

Public Sub OnTimerInterval()
End Sub



From within Class "A" (ClassA):

Implements ITimerFriend

Private Sub ITimerFriend_OnTimerInterval()
    'code for class A to execute on timer interval
End Sub





From within Timer Class (ClassTimer):

Private m_objTimerFriend As ITimerFriend

Public Property Set TimerFriend(NewTimerFriend As ITimerFriend)
    Set m_objTimerFriend = NewTimerFriend
End Property

Public Sub DoSomething()
    'something that calls callback function in std. module
End Sub



The timer class calls the callback function in your standard module, passing in as a parameter, this reference to the TimerFriend object.  Then in your callback, you an do:


Public Function MyCallback(TF As TimerFriend)
    'do stuff

    Call TF.OnTimerInterval
End Function




An example of how this may be implemented from a client interface:


Dim objA  As New ClassA
Dim objTimer As New ClassTimer


Set objTimer.TimerFriend = objA
Call objTimer.DoSomething
0
 
aeklundAuthor Commented:
Thanks for all you input... but perhaps I was a little unclear.  The callback function I'm using is a standard callback function, so I cannot specify any parameters...

Let me layout the battlefield to you guys and see if you can re-arrange my troops so that they work together:

'Class "Timer" (All the timer code)
Option Explicit

Private Declare Function SetTimer Lib "user32" _
  (ByVal hwnd As Long, _
   ByVal nIDEvent As Long, _
   ByVal uElapse As Long, _
   ByVal lpTimerFunc As Long) As Long

Private Declare Function KillTimer Lib "user32" _
  (ByVal hwnd As Long, _
   ByVal nIDEvent As Long) As Long

Private m_iTimer As ITimer
Private cTimers As New Collection
Public bTimerActive As Boolean

Public Function StartTimer(ByVal Milliseconds As Long) As Long
  Dim lTimer As Long
  lTimer = SetTimer(0, 0, Milliseconds, AddressOf TimerProc)
 
  cTimers.Add lTimer, CStr(lTimer)
 
  StartTimer = lTimer
  bTimerActive = True
End Function

Public Sub StopTimer(ByVal lTimer As Long)
  KillTimer 0, lTimer
  cTimers.Remove CStr(lTimer)
End Sub

'Module "basTimer" (The callback function)
Option Explicit

Private Sub TimerProc(ByVal hwnd As Long, _
                      ByVal uMsg As Long, _
                      ByVal idEvent As Long, _
                      ByVal dwTime As Long)
 
  Debug.Print hwnd, uMsg, idEvent, dwTime
End Sub


Now how from within this callback function can I reference the same instance of the class that called it?  I may want to use this code from within a user interface (form) or within another class, I am trying to write re-usable code.

In the callback function hwnd is always 0, umsg is always WM_TIMER, idevent is the actual timer that was created and is unique, this is how I can identify which timer is firing, and dwtime is just a what it is, the time of the timer.

I have increased the points since this is dragging on, and I am basically working on many projects and don't want to beat my head on this one...
0
 
aeklundAuthor Commented:
Hmm... I think I found a way...  here is what I'm thinking:

Declare a public variable in my module as a timer class

then in the timer class initialize event, set that variable to itself.. set variable = me

Now I have reference to the same class from within my module where the callback function is....

Now in my class event I create a friend sub to trigger a public event... and this event could not reside in my user interface, or another class module..

Does that sound like a feasable solution?
0
 
AzraSoundCommented:
Exactly, but the main point being, your standard module MUST know about your timer class...there is no way around that.  Using a public variable to hold the particular instance is a method I have used myself.
0
 
aeklundAuthor Commented:
I'm not too familiar with Implementing classes and using polymorphism in VB.  I have not run into a situation where it is needed, or rather do not have enough knowledge on when best to use polymorphism.

Thanks for all you reply's, and the points go to you AzraSound for helping out and your solution was the closest thus far, and helped me work out the problem.

PS - When is it best to use implements and polymorphism?
0
 
AzraSoundCommented:
>>When is it best to use implements and polymorphism?

It is best when you want to support many different entities that all share some common characteristics.  For example, perhaps you are creating some data gathering tool that can gather data from different devices.  Each device will have its own unique requirements, but they will probably share some common properties and functions.  These common links can be implemented in an Interface class.  Interfaces are good because you can create a common interface, and additional classes may be developed in the future that fit seamlessly into an application that works against that particular interface.  It is not used very often in development in VB that I have seen, but there are occassions when it is very beneficial (in the development of plugins for example).
0
 
aeklundAuthor Commented:
Gotcha... thanks.
0
 
FunkyMeisterCommented:
The class module and standard module (that has the TimerProc which SHOULD be public or atleast Friend for the AddressOf to work) could be made to raise an event, passing off the 4 values from the timers (and perhaps filter some too).  Or perhaps use messages and watch the form's window for a specific message (from the timer), since you can make the Timer Start function require a valid hwnd and when that timer fires, send off a message to the window that set it.  Doing it with messages or events, compile (as AzraSound said) into a DLL and perhaps make the class Friend to the module and use the module as the DLL front end.
0
 
aeklundAuthor Commented:
Funky-

Yes, I realize the TimerProc should be public, when I pasted the code I forgot to make it public, because orginally I had the entire timer functions in one module and not split up into a class/module.  But how can it be used to trigger an event from the 4 values or a filter?

The way I solved it is to put a public variable inside the module that holds the TimerProc function that is set during the timer class initialization function and released on the termination function.

Also, to make this as generic as possible, I do not want to use the hwnd property, in case I want to incorporate this dll/timer class into another dll that does not have forms, so I would not have any hwnd to use therefore can not subclass it like you suggest to watch for window message.

If anyone is interested in my final solution, I would be more than happy to post it.
0
 
FunkyMeisterCommented:
Funny thing is, we're both working on the same thing (I too am working on a DLL to handle input, but from more areas, keyboard, mouse and voice).  Mainly because I hate the keyboard software that came with my Internet keyboard (it's someone's idea of a joke, I know someone's laughed at it, I have a lot).  So, I'm working on the "guts" for now and then plan to make the front end.  Just a few quirks to figure out with respect to the wheels on the mouse (yes, wheelS).  Not found any journal ready code on finding their movement (and direction).  I know when they DO move, but not that.  So whats your keyboard dll for?
0
 
aeklundAuthor Commented:
Funky-
I'm not working on a keyboard dll, this is a timer dll, so I can create true timer and events without a form.

In a more wider description, this timer dll is going into a project I'm creating for monitoring directorys/folders for changes.  When a change is made an event is triggered.

I'm just about finished with the project, and so far everything is working out great...
0
 
FunkyMeisterCommented:
Wouldn't hooking into the system file io (like virus checkers do) to monitor file changes be better than a timer?  (And I'm responding to too much lately it seems, all these hooking and dll questions flying about, I'm getting dizzy.)
0
 
aeklundAuthor Commented:
Yes, I could hook the file i/o, but this will be used for unc paths on other servers, and I don't know of any way to hook into a remove file i/o.. <g>
0
 
FunkyMeisterCommented:
Would the servers be able to run an app?  Reason being, is hook them there and do a "broadcast" message to your "snooper-receiver" to tell it a change happened and where (less network traffic).
0
 
aeklundAuthor Commented:
Hmm... that is a good idea...  It would reduce traffic and would only trigger in the event something changed.. I like it... Thanks for the idea.
0
 
AzraSoundCommented:
0
 
aeklundAuthor Commented:
Thanks, but that does not do everyting I want... something like this is more like it:

http://www.mvps.org/vbnet/code/shell/shchangenotify.htm

Which I have already played with awhile back.
0
 
FunkyMeisterCommented:
No problem aeklund.  I admin a local lan here and I hate it when activity happens without a "noticable" reason.
0
All Courses

From novice to tech pro — start learning today.