EventHandler()
If you do a lot of work with COM components or servers and want to respond to their events, this function, added in VFP 7, is for you. EventHandler() lets you bind a VFP object to a COM object, and when an event fires in the COM object, it runs the identically named method in the VFP. This replaces the VFPCOM DLL that was available for download in VFP 6.
Usage |
lSuccess = EventHandler( oCOMObject, oVFPEventObject [, lUnbind] ) |
Parameter |
Value |
Meaning |
oCOMObject |
Object |
The COM object whose events you want to respond to. |
oVFPEventObject |
Object |
A VFP object that has methods matching (implementing) the event names in oCOMObject. |
lUnbind |
.F. or omitted |
Binds the events from one object to the methods in the other. You'll usually omit this parameter because you're binding events together, not unbinding them. |
.T. |
Unbinds the events. You don't need to explicitly unbind the events; it cleans up after itself if when either one of the objects is released. Oftentimes, it's easier to release an object and re-create it. |
|
lSuccess |
.T. |
The events are successfully bound. |
.F. |
The events are not bound. |
x=NEWOBJECT("myclass") DEFINE CLASS myclass AS session OLEPUBLIC IMPLEMENTS ApplicationEvents2 IN ; "c:\program files\microsoft office\office\msword9.olb" PROCEDURE ApplicationEvents2_Quit() AS VOID * add user code here ENDPROC PROCEDURE ApplicationEvents2_DocumentBeforeSave( ; Doc AS VARIANT, SaveAsUI AS LOGICAL, Cancel AS LOGICAL) ; AS VOID * add user code here ENDPROC ENDDEFINENotice the IMPLEMENTS keyword. You must implement the events interface in your class, and you have to implement every event. Also note that the path to the type library is hard-coded; you'll want to make sure that your program can find it on your users' machines (see DEFINE CLASS for some alternatives ways of handling this). All that's left for you to do is to add the code that runs when the method is called.Once you instantiate your VFP event handler and COM objects, issue EventHandler() to bind the events of the COM object to the same-named methods of the VFP event handler object. The objects stay bound until either of the objects is released. You don't have to explicitly unbind the objects. However, if you pass .T. as the third parameter, you can unbind them without releasing the objects. Do pay very close attention to how your variables are scoped. If either the VFP event handler or the COM object is released, EventHandler() kindly cleans up with no errors or warnings. This is generally considered to be a feature, until you are debugging a situation when one of the objects goes out of scope too soon, leaving the events unbound. To prevent this, incorporate the event handler and the code that uses it into a single class to avoid the problem.
Example |
* Get a reference to the COM object. oWord = CREATEOBJECT("Word.Application") * Get a reference to your event handler object. oMyWordEvents = CREATEOBJECT("MyClass") * Bind them together. lSuccess = EventHandler(oWord, oMyWordEvents) * Here's a relatively long example that shows this in * more detail. It shows some of the events as you * programmatically move around in an ADO Recordset. * To actually run this code, you'll need to substitute * the path of an Access MDB installed on your * machine into the line starting "oConn.Open" below. * Define the objects we'll use (for IntelliSense). LOCAL oConn as ADODB.Connection, ; oRS as ADODB.RecordSet * Create the Connection object and open the Northwind database. oConn = CreateObject('ADODB.Connection') oConn.Open('Provider=Microsoft.Jet.OLEDB.4.0;' + ; 'Data Source=D:\Program Files\Microsoft Visual ' + ; 'Studio\VB98\Nwind.mdb') * Create the Recordset and ADOEventHandler objects and * bind them together. oRS = CreateObject('ADODB.RecordSet') oEvents = CreateObject('ADOEventHandler') EventHandler(oRS, oEvents) * Get all records from the Customers table, then move around * in the Recordset. oRS.CursorLocation = 3 &&adUseClient oRS.CursorType = 3 &&adOpenStatic oRS.ActiveConnection = oConn oRS.Open('select * from Customers') oRS.MoveFirst() oRS.MoveNext() oRS.MoveLast() * Clean up before we exit. EventHandler(oRS, oEvents, .T.) oRS.Close() oConn.Close() * ADOEventHandler class definition, created by dragging * RecordsetEvents interface of ADODB (Microsoft ActiveX * Data Objects 2.6 Library) from Object Browser to this * PRG and then modifying it. DEFINE CLASS ADOEventHandler AS session OLEPUBLIC IMPLEMENTS RecordsetEvents IN ADODB.RecordSet PROCEDURE RecordsetEvents_WillChangeField( ; cFields AS Number, Fields AS VARIANT, ; adStatus AS VARIANT @, pRecordset AS VARIANT) ; AS VOID * add user code here ENDPROC PROCEDURE RecordsetEvents_FieldChangeComplete(; cFields AS Number, Fields AS VARIANT, ; pError AS VARIANT, adStatus AS VARIANT @, ; pRecordset AS VARIANT) AS VOID * add user code here ENDPROC PROCEDURE RecordsetEvents_WillChangeRecord(; adReason AS VARIANT, cRecords AS Number, ; adStatus AS VARIANT @, pRecordset AS VARIANT) ; AS VOID * add user code here ENDPROC PROCEDURE RecordsetEvents_RecordChangeComplete( ; adReason AS VARIANT, cRecords AS Number, ; pError AS VARIANT, adStatus AS VARIANT @, ; pRecordset AS VARIANT) AS VOID * add user code here ENDPROC PROCEDURE RecordsetEvents_WillChangeRecordset(; adReason AS VARIANT, adStatus AS VARIANT @, ; pRecordset AS VARIANT) AS VOID * add user code here ENDPROC PROCEDURE RecordsetEvents_RecordsetChangeComplete( ; adReason AS VARIANT, pError AS VARIANT, ; adStatus AS VARIANT @, pRecordset AS VARIANT) ; AS VOID * add user code here ENDPROC PROCEDURE RecordsetEvents_WillMove(; adReason AS VARIANT, adStatus AS VARIANT @, ; pRecordset AS VARIANT) AS VOID lcMessage = 'WillMove event:' + chr(13) + 'Reason: ' * ADO EventReasonEnum values #DEFINE ADRSNMOVE 10 #DEFINE ADRSNMOVEFIRST 12 #DEFINE ADRSNMOVENEXT 13 #DEFINE ADRSNMOVEPREVIOUS 14 #DEFINE ADRSNMOVELAST 15 DO CASE CASE adReason = ADRSNMOVE lcMessage = lcMessage + 'move' CASE adReason = ADRSNMOVEFIRST lcMessage = lcMessage + 'move first' CASE adReason = ADRSNMOVENEXT lcMessage = lcMessage + 'move next' CASE adReason = ADRSNMOVELAST lcMessage = lcMessage + 'move last' ENDCASE WAIT WINDOW lcMessage ENDPROC PROCEDURE RecordsetEvents_MoveComplete( ; adReason AS VARIANT, pError AS VARIANT, ; adStatus AS VARIANT @, pRecordset AS VARIANT) ; AS VOID WAIT WINDOW 'MoveComplete event' ENDPROC PROCEDURE RecordsetEvents_EndOfRecordset( ; fMoreData AS LOGICAL @, adStatus AS VARIANT @, ; pRecordset AS VARIANT) AS VOID * add user code here ENDPROC PROCEDURE RecordsetEvents_FetchProgress( ; Progress AS Number, MaxProgress AS Number, ; adStatus AS VARIANT @, pRecordset AS VARIANT) ; AS VOID WAIT WINDOW 'FetchProgress: ' + TRANSFORM(Progress) + ; ' of ' + TRANSFORM(MaxProgress) ENDPROC PROCEDURE RecordsetEvents_FetchComplete( ; pError AS VARIANT, adStatus AS VARIANT @, ; pRecordset AS VARIANT) AS VOID WAIT WINDOW 'FetchComplete' ENDPROC ENDDEFINE |
See Also |