It is many years since I did anything with FoxPro, but I have a legacy system that needs work. Okay, I can call a COM-based application such as MapPoint or Excel from FoxPro. I've done that before. However, how do I pass a function or object method as an event callback? Is it even possible? (I can't find anything online or the FoxPro books I've managed to track down)
The following is a VB6 example of what I mean, taken from the MapPoint documentation. As it happens OnConnection()
is itself a callback; but the call to moaApp.AddCommand()
passes a reference to a callback function ( SayHello()
) to MapPoint (moApp
), as a menu callback.
Not that it matters for the question, but I'm probably going to need to trap the Save, Quit, and Menu callback events.
Dim moaApp As MapPoint.Application
Public Sub SayHello()
MsgBox "Hello"
End Sub
Private Sub AddinInstance_OnConnection(ByVal Application As Object, ByVal ConnectMode As
AddInDesignerObjects.ext_ConnectMode, ByVal AddInInst As Object, custom() As Variant)
On Error GoTo error_handler
Set moaApp = Application
'Add this command to the menu (HOW DO I DO THIS IN FOXPRO?)
moaApp.AddCommand "Saying Hello", "SayHello", Me
Exit Sub
error_handler:
MsgBox Err.Description
End Sub
Thanks to the lead from @Alan B, I've managed to get it working...
Events are caught by creating a COM class that implements the required event interface. All events in the interface have to be implemented, although they can be empty implementations.
E.g.
&& Create an event handler
oHandler = CREATEOBJECT("MapPointEventHandler")
&& Connect our _ApplicationEvents implementation
EVENTHANDLER( oMyMapPointApp, oHandler)
&& Here is our event handler
DEFINE CLASS MapPointEventHHandler AS Session OLEPUBLIC
IMPLEMENTS _ApplicationEvents IN "MapPoint.Application"
&& Call back when MapPoint Quits
PROCEDURE _ApplicationEvents_Quit()
MESSAGEBOX("QuitHandler called")
ENDPROC
&& Event indicates MapPoint is about to close
PROCEDURE _ApplicationEvents_BeforeClose( bcancel as logical) AS VOID
MESSAGEBOX("before close called")
ENDPROC
&& These events are not used here, but must be defined for COM/class compatibility
PROCEDURE _ApplicationEvents_BeforeSave( SaveAsUI AS logical @, bcancel as logical) AS VOID
*? PROGRAM()
ENDPROC
PROCEDURE _ApplicationEvents_New() AS VOID
*? PROGRAM()
ENDPROC
PROCEDURE _ApplicationEvents_Open() AS VOID
*? PROGRAM()
ENDPROC
ENDDEFINE
Methods can also be passed (eg. for menu items), but these cannot be to the same class. You need to implement one class for each event handler interface you wish to implement, and a separate class to handle the menu callbacks.
Here is an example with a menu item:
&& Create a menu handler
oMyMenu = CREATEOBJECT("MapPointMenuHandler")
&& Add our Tools menu entries and hook them up
oMyMapPointApp.AddCommand("Custom Menu Item", "MyMenuCallBack", oMyMenu)
&& This class implements the Tools menu callbacks
&& *** NOTE: MessageBox will appear UNDER MapPoint
DEFINE CLASS MapPointMenuHandler AS Session OLEPUBLIC
PROCEDURE MyMenuCallback()
MESSAGEBOX("Main Menu callback")
ENDPROC
ENDDEFINE