Sendclass substitute

This forum is meant for questions and discussions about the X# language and tools
Post Reply
stefan.ungemach
Posts: 71
Joined: Thu Jul 15, 2021 10:46 am
Location: Germany

Sendclass substitute

Post by stefan.ungemach »

In my VO Code I use Sendclass to modify a SDK constructor's behaviour. This looks like this and worked fine for more than a decade:

(this is part of my dbServer_Subclass INit() method)
if !lFromLocked // no special actions needed
SUPER( )
else
SendClass( self, #Init, #DataServer ) // instead of SUPER:Init
(my own constructor code)
endif


In XSharp SendClass is no longer supported, so I want to try something like this:

if !lFromLocked // no special actions needed
SUPER( )
else
var t := FindClass(#DataServer)
var constructors := t:GetConstructors()
var ctor := constructors:FirstOrDefault()
if ctor != null
try
ctor:Invoke()
(my own constructor code)
catch as Error
throw
catch e as Exception
throw Error{e:GetInnerException()}
end try
endif
endif


Unfortunately, System.Reflection.ConstructorInfo.Invoke wants a handful of parameters which I don't understand. Could someone help me out here - or is my approach wrong anyway?
User avatar
robert
Posts: 4518
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Sendclass substitute

Post by robert »

Stefan,
Smart, but dirty solution.
I would recommend to call the Invoke overload that accepts an array of Objects
and then use the function _ArrayToObjectArray() to convert a normal VO array of arguments to OBJECT[]
and pass that to the constructor.

Code: Select all

ctor:Invoke(  _ArrayToObjectArray({})) // for no arguments
or

Code: Select all

ctor:Invoke(  _ArrayToObjectArray({1,2,3})) // with some example arguments.
Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
User avatar
Chris
Posts: 4898
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Sendclass substitute

Post by Chris »

Hi Stefan,

It's not necessarily wrong, but it's definitely very naughty :)

It can work though, the CLIPPER calling convention constructors/methods expect (they've been implemented in X# this way) a single ARRAY of USUALs as an argument , containing the actual arguments to be passed to it. The ctor:Invoke() in turn expects the arguments to send to the constructor in an ARRAY of OBJECTs. So you need to send it such an array, containing a single element, the former array of usuals. A little complicated, but this code should do the trick:

Code: Select all

LOCAL aArgsToCtor AS USUAL[] // syntax to define an ARRAY of USUALs
aArgsToCtor := <USUAL>{} // instantiating the array, with zero elements. Also this would do the same: aArgsToCtor := USUAL[]{0}
LOCAL oArgToInvoke AS OBJECT[]
oArgToInvoke := <OBJECT>{aArgsToCtor}
		
ctor:Invoke(oArgToInvoke)
Note that in this particular case, the first array is empty, because the constructor of the DataWindow class does not need any params. If you instead wanted to call the constructor of DataWindow for example, you would have to change the code to something like

Code: Select all

aArgsToCtor := <USUAL>{oParent , oResource , _GetInst()}
hth
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
stefan.ungemach
Posts: 71
Joined: Thu Jul 15, 2021 10:46 am
Location: Germany

Sendclass substitute

Post by stefan.ungemach »

Thank you - especially - Array2ObjectArray is a very useful hint which suits me for many other occasions.

The reason why I need the dirty trick (I'm telling this because maybe there is a better approach):

We need to stick to DBFs due to a reporting software which we mußte maintain for some more years. We as also need to protect the database against theft or malware Wunder a user account. So we strip the users (clients) of all rights to the directory and redirect all file operations though some server side stored procedures. Since the dbServer class has several internal uses of file functions we use the dirty trick to inject our own Filespec subclass and our file_lockable() functions which mask the deviation.

If there is another way to put a dbServer subclass on top of a filesystem layer like ours I'd be happy to learn about it.

TiA Stefan
User avatar
Chris
Posts: 4898
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Sendclass substitute

Post by Chris »

Hi Stefan,

Hard to tell without seeing exactly what you are doing in your own constructor replacement, but for using a custom FileSpec, I think you could just pass it as a first argument to the standard DBServer constructor. But I'm sure you're doing more complicated things than that in the code.

.
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
stefan.ungemach
Posts: 71
Joined: Thu Jul 15, 2021 10:46 am
Location: Germany

Sendclass substitute

Post by stefan.ungemach »

Hi Chris,

in VO passing a custoim FileSpec didn't suffice to do the job since there were some aditional file()-calls within the SDK dbServer code. In XSharp I'm actually trying to pass the custom FileSpec as a first parameter, which of course compiles because at a first glance I didn't find any direct file accesses beyond FileSpec in the SDK code. If this simple approach tests fine I'll be more than happy to drop one of my "dirty tricks" ;)
Post Reply