Synergex.SynergyDE.IOExtensions.IOHooks

WTSupported in traditional Synergy on Windows
WNSupported in Synergy .NET on Windows
USupported on UNIX
VSupported on OpenVMS
namespace Synergex.SynergyDE.IOExtensions
class IOHooks
    protected readonly channel,                 int
    protected syserr,                           int
    protected sysstv,                           int

The IOHooks class makes it possible to perform custom I/O without changing any code in your existing I/O routines. Unlike the other system-supplied classes, you don’t call the hook routines yourself. Instead, IOHooks provides 4 constructors and 17 pre- and post-operation virtual hook methods that you create using the specified names and method signatures to do whatever you want them to do. If implemented, these methods are then called automatically in conjunction with other operations (for example, a FIND, a READ, a WRITE, etc.). (See Pre-operation hook methods and Post-operation hook methods for specific details.) Your implementation of these methods must exactly match the method signature you’re overriding; otherwise, you’ll get a “No suitable Method found to override” error (NOOVR) when compiling. You can extend these methods to implement dynamic operation logging, perform pre- or post-I/O processing in your application, or whatever else you need them to do.

The class that you create by extending the IOHooks base class must implement at least one constructor and override at least one hook method, depending on which I/O operations you need. In your application itself, you’ll create an instance of your class and register it as a file I/O event handler for a channel or Select statement.

For example, if you want to perform some processing before and after a READS operation, you’ll override the READS pre- and post-operation hook methods. Your custom pre-operation method will then be executed before any READS occurs. The READS itself is issued as soon as your method exits, followed immediately by your post-operation hook method. Upon exit of the post-operation hook method, your application resumes.

Global I/O hooks

You can use I/O hooks globally on Windows and UNIX when you create a SYN_GLOBALHOOKS_OPEN routine. With regular (non-global) I/O hooks, you add an IOHooks constructor somewhere in your code, and then when that code is executed, your I/O hooks become active. For global I/O hooks, you instead add the IOHooks constructor to your SYN_GLOBALHOOKS_OPEN() implementation, and then after each OPEN, your routine can activate I/O hooks on chosen files and/or open modes.

Using global I/O hooks instead of non-global I/O hooks offers one big advantage. With standard I/O hooks, you need to link in a source module that contains your IOHooks logic and explicitly call a routine or execute some code that references that logic. With global hooks, you can activate the hooks simply by linking in the source module containing your IOHooks logic. Your application can be running without hooks, and then when you link in the module with IOHooks (and your SYN_GLOBALHOOKS_OPEN() implementation), your hooks become fully active, without modifying the rest of your application. In other words, you don’t need to conditionalize your application to instantiate the hooks object; all you need to do is link it in.

To use global I/O hooks with Synergy .NET, your I/O hooks module must be included in your compile.

Constructors

IOHooks

public IOHooks(channel)

Creates or replaces a new instance of the I/O event handler class associated with the specified channel opened to a file (n).

or

public IOHooks(Select.From)

Creates or replaces a new instance of the I/O event handler class associated with a file referenced in a From object.

or

public IOHooks(channel, premask, postmask)

Creates or replaces a new instance of the I/O event handler class associated with the specified channel opened to a file (n) and two bit masks (IOEventMask).

or

method IOHooks(Select.From, premask, postmask)

Creates or replaces a new instance of the I/O event handler class associated with a file referenced in a From object and two bit masks (IOEventMask).

Methods

IOReset

public IOReset(premask, postmask), void

Dynamically changes hook methods that are to be used in an existing event handler instance. See the Discussion.

premask

The pre-operation hook routines to be used. (IOEventMask)

postmask

The post-operation hook routines to be used. (IOEventMask)

Pre-operation hook methods

find_pre_operation_hook

public virtual method find_pre_operation_hook, void
    mismatch in optional key, n
    in optional in_rfa,       a
    in optional keynum,       n
    in flags,                 IOFlags
proc
.
.
.
endmethod

If implemented, called before a FIND operation.

key

(optional) Key value passed to the FIND. (MISMATCH n)

in_rfa

(optional) Incoming RFA/GRFA via the RFA qualifier. (a)

keynum

(optional) Numeric KEYNUM value. (n)

flags

Set to any IOFlags present. (IOFlags)

read_pre_operation_hook

public virtual method read_pre_operation_hook, void
    mismatch in optional key,  n
    in optional in_rfa,        a
    in optional keynum,        n
    in flags,                  IOFlags
proc
.
.
.
endmethod

If implemented, called before a READ operation.

key

(optional) Key value passed to the READ. (MISMATCH n)

in_rfa

(optional) Incoming RFA/GRFA via the RFA qualifier. (a)

keynum

(optional) Numeric KEYNUM value. (n)

flags

Set to any IOFlags present. (IOFlags)

reads_pre_operation_hook

public virtual method reads_pre_operation_hook, void
    in flags,      IOFlags
proc
.
.
.
endmethod

If implemented, called before a READS operation.

flags

Set to any IOFlags present. (IOFlags)

write_pre_operation_hook

public virtual method write_pre_operation_hook, void
    inout buffer,              a
    in optional recnum,        n
    in optional in_rfa,        a
    in flags,                  IOFlags
proc
.
.
.
endmethod

If implemented, called before a WRITE operation (or AlphaEnumerator.Current set property or AlphaEnumerator.SparseUpdate when using Select).

buffer

Record to be written. (a)

recnum

(optional) Alphanumeric record number to be written (non-ISAM) or not ^PASSED (ISAM). (n)

in_rfa

(optional) Incoming RFA/GRFA via the RFA qualifier. (a)

flags

Set to any IOFlags present. (IOFlags)

writes_pre_operation_hook

public virtual method writes_pre_operation_hook, void
    inout buffer,              a
    in flags,                  IOFlags
proc
.
.
.
endmethod

If implemented, called before a WRITES operation.

buffer

Record to be written. (a)

flags

Set to any IOFlags present. (IOFlags)

store_pre_operation_hook

public virtual method store_pre_operation_hook, void
    inout buffer,          a
    in flags,              IOFlags
proc
.
.
.
endmethod

If implemented, called before a STORE operation.

buffer

Record to be written. (a)

flags

Set to any IOFlags present. (IOFlags)

delete_pre_operation_hook

public virtual method delete_pre_operation_hook, void
proc
.
.
.
endmethod

If implemented, called before a DELETE operation (or the AlphaEnumerator.DeleteCurrent() or RestrictedAlphaEnumerator.DeleteCurrent() method when using Select).

unlock_pre_operation_hook

public virtual method unlock_pre_operation_hook, void
    in optional rfa,                    a
    in flags,                           IOFlags
proc
.
.
.
endmethod

If implemented, called before an UNLOCK or FREE operation. When UNLOCK is called, the rfa parameter will either contain the RFA that was specified on the UNLOCK statement or it won't be passed. When FREE is called, -1 is passed in the rfa parameter. Therefore, you can detect the difference between (UNLOCK CH), (UNLOCK CH, RFA), and XCALL FREE() by using the syntax

(^i(rfa(1:4)) == -1 .and. ^i(rfa(5:2)) == -1)

rfa

(optional) Incoming RFA/GRFA if ^MATCH:RFA and RFA qualifiers were specified. (a)

flags

Set to any IOFlags present. (IOFlags)

close_pre_operation_hook

public virtual method close_pre_operation_hook, void
    in flags,                   IOFlags
proc
.
.
.
endmethod

If implemented, called before a CLOSE operation.

flags

Set to any IOFlags present. (IOFlags)

Close_pre_operation_hook() is called only when a CLOSE statement is explicitly called (in traditional Synergy only) on normal program termination or an explicit STOP statement. Under abnormal termination (an unhandled exception or untrapped error), the close_pre_operation_hook() method will not be called. Therefore, if you want to rely on close_pre_operation_hook() always being called, but you haven’t guarded against unhandled exceptions (or untrapped errors), you can do one of the following:

In either case, when an error is caught, you can explicitly close all opened channels. (If your CLOSE hook routine does I/O, be careful of the order in which you close your channels.)

The first example below uses TRY-CATCH to catch unhandled exceptions.

main
...
proc
    try
      begin
        {Main routine code}
      end
    catch (e)          ;Catch anything unexpected
      begin
        close 1 thru 1024
      end
    finally
      begin
        close 1 thru 1024
      end
end

The following example uses $ERR_CATCH to handle untrapped errors.

main
    ...
proc
    onerror ($ERR_CATCH) close_files
    {Main routine code}
close_files,
    close 1 thru 1024
end

Post-operation hook methods

find_post_operation_hook

public virtual method find_post_operation_hook, void
    mismatch in optional key,           n
    in optional out_rfa,                a
    in optional keynum,                 n
    in flags,                           IOFlags
    inout error,                        int
proc
.
.
.
endmethod

If implemented, called after a FIND operation.

key

(optional) Key value passed to the FIND. (MISMATCH n)

out_rfa

(optional) RFA/GRFA being returned via the GETRFA qualifier. (a)

keynum

(optional) Numeric KEYNUM value. (n)

flags

Set to any IOFlags present. (IOFlags)

error

Set to a runtime error number that occurred during the FIND or else 0. (int)

read_post_operation_hook

public virtual method read_post_operation_hook, void
    inout buffer,                       a
    mismatch in optional key,           n
    in optional out_rfa,                a
    in optional keynum_or_table,        n
    in flags,                           IOFlags
    inout error,                        int
proc
.
.
.
endmethod

If implemented, called after a READ operation (or AlphaEnumerator.Current get property, RowEnumerator.Fill(), or RowEnumerator.indexer[]), or during an iteration of a FOREACH on a Select object).

Important

If the reads_post_operation_hook method is implemented and part of the I/O hooks creation mask, it will override read_post_operation_hook. To enable read_post_operation_hook, you must disable or remove reads_post_operation_hook.

buffer

Record that was read. (a)

key

(optional) Key value passed to the READ. (MISMATCH n)

out_rfa

(optional) RFA/GRFA being returned via the GETRFA: qualifier. (a)

keynum_or_table

(optional) Numeric KEYNUM value or the table index on a Join. (n)

flags

Set to any IOFlags present. (IOFlags)

error

Set to a runtime error number that occurred during the READ or else 0. (int)

reads_post_operation_hook

public virtual method reads_post_operation_hook, void
    inout buffer,                       a
    in optional out_rfa,                a
    in flags,                           IOFlags
    inout error,                        int
proc
.
.
.
endmethod

If implemented, called after a READS operation. This method has been deprecated when using the Select class, to be replaced by the read_post_operation_hook.

Important

If the reads_post_operation_hook method is implemented and part of the I/O hooks creation mask, it will override read_post_operation_hook. To enable read_post_operation_hook, you must disable or remove reads_post_operation_hook.

buffer

Record that was read. (a)

out_rfa

(optional) RFA/GRFA being returned via the GETRFA: qualifier. (a)

flags

Set to any IOFlags present. (IOFlags)

error

Set to a runtime error number that occurred during the READS or else 0. (int)

write_post_operation_hook

public virtual method write_post_operation_hook, void
    inout buffer,                       a
    in optional recnum,                 n
    in optional out_rfa,                a
    in flags,                           IOFlags
    inout error,                        int
proc
.
.
.
endmethod

If implemented, called after a WRITE operation (or AlphaEnumerator.Current set property or AlphaEnumerator.SparseUpdate when using Select).

buffer

Record that was written. (a)

recnum

(optional) Alphanumeric record number that was written (non-ISAM) or not ^PASSED (ISAM). (n)

out_rfa

(optional) RFA/GRFA being returned via the GETRFA: qualifier. (a)

flags

Set to any IOFlags present. (IOFlags)

error

Set to a runtime error number that occurred during the WRITE or else 0. (int)

writes_post_operation_hook

public virtual method writes_post_operation_hook, void
    inout buffer,                       a
    in optional stored_rfa,             a
    in flags,                           IOFlags
    inout error,                        int
proc
.
.
.
endmethod

If implemented, called after a WRITES operation.

buffer

Record that was written. (a)

stored_rfa

(optional) To be loaded with an RFA or GRFA if GETRFA: qualifier was specified. (a)

flags

Set to any IOFlags present. (IOFlags)

error

Set to a runtime error number that occurred during the WRITES or else 0. (int)

store_post_operation_hook

public virtual method store_post_operation_hook, void
    inout buffer,                       a
    in optional stored_rfa,             a
    in flags,                           IOFlags
    inout error,                        int
proc
.
.
.
endmethod

If implemented, called after a STORE operation.

buffer

Record that was written. (a)

stored_rfa

(optional) To be loaded with an RFA or GRFA if GETRFA: qualifier was specified. (a)

flags

Set to any IOFlags present. (IOFlags)

error

Set to a runtime error number that occurred during the STORE or else 0. (int)

delete_post_operation_hook

public virtual method delete_post_operation_hook, void
    inout error,                        int
proc
.
.
.
endmethod

If implemented, called after a DELETE operation (or the AlphaEnumerator.DeleteCurrent() or RestrictedAlphaEnumerator.DeleteCurrent() method when using Select).

error

Set to a runtime error number that occurred during the DELETE or else 0. (int)

unlock_post_operation_hook

public virtual method unlock_post_operation_hook, void
    in flags,                           IOFlags
    inout error,                        int
proc
.
.
.
endmethod

If implemented, called after an UNLOCK or FREE operation.

flags

Set to any IOFlags present. (IOFlags)

error

Set to either a runtime error number that occurred during the UNLOCK or FREE or else 0. (int)

Dispose  

protected override method Dispose, void
    in disposing, boolean
proc
.
.
.
endmethod

(Synergy .NET only) If implemented, called before the dispose operation.

disposing

Returns true if Dispose() was called explicitly, or false if Dispose() was called implicitly as the object was being destroyed. (boolean)

Note

The exact time when the finalizer executes is nondeterministic and occurs on a different thread. To know when the finalizer executed, you can implement a Dispose() method, which is called when either the hooked channel is closed or the IOHooks object is overwritten; you can also explicitly call IOHooks.Dispose(). You should implement the Dispose() method on .NET in situations where you would have created an overridden destructor in traditional Synergy (for example, to close a log file channel).

Exception hook method

reconnect_hook

public virtual method reconnect_hook, boolean
    in opflag, IOEventMask
    in error, int
proc
    mreturn false
endmethod

Called during connection recovery after the retry time interval has expired and prior to signaling $ERR_SRVCONRTY. If this method is not implemented, false is returned and the $ERR_SRVCONRTY error is generated. By implementing reconnect_hook() and simply returning true, you can choose a different behavior (for example, popping up a message box to query the user or issuing code to do some exception processing). See the Discussion below for more information.

opflag

Set to the IOEventMask flag, indicating the operation being retried. (IOEventMask)

error

Set to the error $ERR_SRVCONRTY. Also, IOHooks.Syserr will be set to the system error number. (int)

Discussion

Because the runtime calls the hook routines, it controls which optional parameters are passed, based on the information available and the context. For hook methods that include optional parameters at the statement level (such as RFA:), you must use the ^PASSED function to test whether the parameter was passed before referencing it. If you don’t use ^PASSED on an optional argument and that argument isn’t passed, an “Argument missing” error ($ERR_ARGMIS) will occur.

The IOHooks constructors take either one or three parameters and have the following signatures:

IOHooks(channel)
new IOHooks(channel, premask, postmask)

or

new IOHooks(Select.From)
new IOHooks(Select.From, premask, postmask)

Only one IOHooks class object can be registered to each channel.

You will need to add code to create a new instance of your event handler class, passing the channel or the Select.From object on which the desired file is open. All event handler methods implemented in the class will be hooked and used during I/O operations.

Note

It is not necessary to assign the resulting object to a handle unless you intend to use the IOReset() method.

For example,

(void)new myhooks(ch)           ;Hook a channel

or

(void)new myhooks(fobj)         ;Hook a Select channel

or

hnd = new myhooks(ch)           ;Save hnd for use later
Note

When managing file channels using one of the Select class From constructors that specifies the filename, the channel number is not available, so you will need to use one of the IOHooks constructors that takes a Select.From object.

When using the Select class, an iteration on the selection (or AlphaEnumerator.MoveNext() or RowEnumerator.MoveNext()) should be hooked using the READS pre- and post-hooks; a record update using the RowEnumerator.Current property should be hooked using the WRITE pre- and post-hooks; and a record deletion using the AlphaEnumerator.DeleteCurrent() method should be hooked using the DELETE pre- and post-hooks. No other I/O operations are hooked while a Select is occurring on a channel (except STORE, UNLOCK, and CLOSE, which can still be done on a Select channel).

A general IOHooks class can be used to control several different channels where different I/O operations are required. The premask and postmask values are used to specify those operations; each bit in the premask and postmask parameters represents an I/O hook method that has been overridden in a class that extends the IOHooks class. If you don’t want to hook all of the methods implemented in the class, you can pass the mask values for the pre- and post-operation flags to indicate which hook methods in the event handler class you do want to use. For example,

hnd = new myhooks(ch, IOEventMask.Read, IOEventMask.Read)

Bits that are set create pre- or post-event handler hooks for the I/O operations that the bits represent. Bits that are not set clear pre- or post-event handler hooks for the I/O operations that the bits represent.

To change which implemented hook methods are to be used during I/O operations, using an instance of the event handler class, you can explicitly call the IOReset() method with new mask values for pre- and post-operation flags. For example,

hnd.IOReset(IOEventMask.Reads, IOEventMask.Reads|IOEventMask.Store)

To unregister the event handler without closing the file, call IOReset() with the Clear mask values for both pre- and post-operation mask. For example,

hnd.IOReset(IOEventMask.Clear, IOEventMask.Clear)

To reset the mask values for both pre- and post-operations back to all methods implemented in the class, you can explicitly call IOReset() like this:

hnd.IOReset(IOEventMask.Auto, IOEventMask.Auto)

As the application executes, I/O operations on hooked channels execute your event handler methods immediately before the operation (pre-hook) and/or immediately after the operation (post-hook). When the registered channel is closed, the event handler object is unregistered automatically.

Note

Parameters that are defined INOUT, such as the read or write buffer, can be modified by the hook methods, resulting in altered data read or written. This feature can be very useful (if you want to encrypt data transparently, for example), but it can also be very dangerous, because it hides what goes into and comes out of a file.

To trap an $ERR_SRVCONRTY error during an I/O operation, you must implement your own hooks class that extends the IOExtensions.IOHooks class and overrides the reconnect_hook() method. Returning true from your reconnect_hook() method tells the I/O operation to reset the retry time interval and try again. This method will continue to be called until either the connection is re-established or your reconnect_hook() method returns false. For more information, see Using connection recovery (Windows).

See also