Translate some Visual Studio code

Posted by DenDuze on 03-Oct-2018 08:35

Hi,

We need to replace some Visual studio code with Progress code but I have no idea how i need to translate the following:
ExtensionManager.Instance.Invoke(Of IPaymentHandlerExtension)(Sub(x) x.HandlePayment(paymentId, amount, comment))

Can someone give me a direction?

Regards
Didier

All Replies

Posted by gus bjorklund on 03-Oct-2018 13:28

I doubt that anyone on this forum know what "ExtensionManager.Instance.Invoke(Of IPaymentHandlerExtension)(Sub(x) x.HandlePayment(paymentId, amount, comment))” means.

You will have to supply a lot more information about your environment before anyone will be able to assist.

What OpenEdge version?

Of what software is ExtensionManager a part?

What are the datatypes being passed in the function call ?

What are the expected return values?

Posted by jquerijero on 03-Oct-2018 14:17

[quote user="DenDuze"]

Hi,

We need to replace some Visual studio code with Progress code but I have no idea how i need to translate the following:
ExtensionManager.Instance.Invoke(Of IPaymentHandlerExtension)(Sub(x) x.HandlePayment(paymentId, amount, comment))

Can someone give me a direction?

Regards
Didier

[/quote]

Not so sure if ExtensionManager Invoke method is just the System.Reflection Invoke method, but here is a sample code to dynamically invoke a class method in ABL.

DEFINE VARIABLE oMethod AS System.Reflection.MethodInfo NO-UNDO.
DEFINE VARIABLE oType AS System.TYPE NO-UNDO.
DEFINE VARIABLE bindingAttr AS BindingFlags NO-UNDO.
DEFINE VARIABLE arrayVar AS System.Object EXTENT 2 NO-UNDO.

bindingAttr = BindingFlags:Instance.
bindingAttr = CAST(EnumHelper:Or(bindingAttr, BindingFlags:NonPublic), BindingFlags).
oType = Progress.Util.TypeHelper:GetType("System.Windows.Forms.Control"). // IPaymentHandlerExtension
oMethod = oType:GetMethod("RemovePendingMessages", bindingAttr). // HandlePayment

IF VALID-OBJECT(oMethod) THEN
  oMethod:Invoke(THIS-OBJECT, arrayVar).

THIS-OBJECT - is the object instance (x in your sample)
arrayVar - parameters to method you are calling 

Posted by DenDuze on 04-Oct-2018 01:56

Hi Gus/jquerijero,

The problem is that I also do not know what all this does.

We need to put some existing functionality (currently written in vb) in our Progress application.

The person who implemented that functionality only executed ths following code:

' Handle payments

If RadioButtonShop.Checked = True Then

    For Each row As DataGridViewRow In DataGridViewInvoicePayments.Rows

         Dim amount = cVerGeneralSubsAndFunctions.ReturnSingleIfNull(DataGridViewInvoicePayments("PaymentAmount", row.Index).Value)

          If amount < 0.01 Then Continue For

               Dim comment = String.Format("{0}-{1}/{2}", TextBoxDocumentNumber.Text, VERPigoMainForm.strBranchCode, Strings.Right(MaskedTextBoxCustomerNumber.Text, VERPigoMainForm.intLengthCustomerNumber))

         Dim paymentId = CInt(row.Cells("PaymentMethodID").Value)

               ExtensionManager.Instance.Invoke(Of IPaymentHandlerExtension)(Sub(x) x.HandlePayment(paymentId, amount, comment))

   Next

End If

He tells me that when he calls that ExtensionManager:instance:Invoke a form is shown where the user can make some payments.

So the easiest way for me to implement that functionality is try to do the same but I have no idea what that line of code just does (I'm no .net programmer, I understand a bit but ...)

If needed I can provide you the ExtentionManager.vb file but maybe the comment on top of that file can help

This class will scan a directory for dll's with types that implement IExtension

'Any types found are instanciated and available to call using the ExtensionMethod.Invoke(Of T) method

The Invoke method has the following code:

Public Sub Invoke(Of T)(act As Action(Of T))

 For Each extension As IExtension In _extensions.Where(Function(e) GetType(t).IsAssignableFrom(e.GetType))

      Dim extOfT = DirectCast(extension, T)

      act(extOfT)

   Next

End Sub

The IPaymentHandlerExtension has the following code:

Public Interface IPaymentHandlerExtension

   Inherits IExtension

   Function HandlePayment(paymentMethodId As Integer, amount As Single, comment As String) As Boolean

End Interface

There is also a class AdyenPaymentHandlerExtension that Implemants the iPaymentHandlerExtension where the HandlePayment method is implemented

For the rest there are some other files but as far as I know (hope) I do not need to know what these do because when I could replace that

ExtensionManager.Instance.Invoke(Of IPaymentHandlerExtension)(Sub(x) x.HandlePayment(paymentId, amount, comment))

It should hopefully work (that's what that person who made the vb-code said)

regards

Didier

Posted by Mike Fechner on 04-Oct-2018 02:06

VB.NET … not my speciality.
 
But if I recall right, the (Of IPaymentHandlerExtension) is the VB.NET syntax for generic methods.
 
If that’s the case, you’ll need to use reflection as the ABL does not support accessing .NET generic methods (on non generic types).
 
 

Posted by DenDuze on 04-Oct-2018 02:25

Hi Mike,

I can only see a Telerik.WinControls.ReflectionHelper in the Class Browser.

I guess that one is only for Telerik controls.

In my case it's not a Telerik controls so ....

Regards

Didier

Posted by Mike Fechner on 04-Oct-2018 02:34

That ReflectionHelper is an ABL class. Source code is in the Github repo.

Posted by DenDuze on 04-Oct-2018 02:57

@Mike: ok but i guess that belongs to the consulting SmartComponent framework so i can't use that - or I'm I wrong about that? I never used something like this .

@jquerijero: I also tried your approch but the oMethod is not a valid-object so I must do something wrong here.

I used the following code to test:

define variable oMethod as System.Reflection.MethodInfo no-undo.

define variable oType as System.Type no-undo.

define variable bindingAttr as System.Reflection.BindingFlags no-undo.

define variable arrayVar as System.Object extent 3 no-undo.

bindingAttr = System.Reflection.BindingFlags:Instance.

bindingAttr = CAST(Progress.Util.EnumHelper:or(bindingAttr, System.Reflection.BindingFlags:NonPublic), System.Reflection.BindingFlags).

oType = Progress.Util.TypeHelper:GetType("Verpigo.Extensibility.IPaymentHandlerExtension").

/* here both object are valid */

message program-name(1) skip valid-object(oType) skip valid-object(bindingAttr)

view-as alert-box.

oMethod = oType:GetMethod("HandlePayment", bindingAttr). // HandlePayment

/* this gives me false back whle the function is defined there like

Function HandlePayment(paymentMethodId As Integer, amount As Single, comment As String) As Boolean */

message program-name(1) skip 'omethod ' valid-object(oMethod)

view-as alert-box.

regards

Didier

Posted by Mike Fechner on 04-Oct-2018 03:52

The bits on Github are released under the MIT license.

Posted by DenDuze on 04-Oct-2018 04:47

ok, tried it with that but It's unclear to me how I need to use that in my case

I tried the following method PUBLIC System.Object InvokeGenericMethod (Object, character, character)

def var o as Verpigo.Extensibility.ExtensionManager.

def var o2 as PaymentExtension_Adyen.AdyenPaymentHandlerExtension.

o2 = CAST (ReflectionHelper:InvokeGenericMethod(o,

                                                                                        "HandlePayment",

                                                                                       "Verpigo.Extensibility.ExtensionManager").

But I get error 205

I'm sure I'm doing something wrong (but that's normal because I have no idea what this does)

The code to translate is:

ExtensionManager.Instance.Invoke(Of IPaymentHandlerExtension)(Sub(x) x.HandlePayment(paymentId, amount, comment))

Please advise

Posted by Mike Fechner on 04-Oct-2018 04:54

For those of us, that don’t know 18000 Progress error messages by heard, what is 205?
 
But your CAST is missing the second argument, the target type:
 

o2 = CAST (ReflectionHelper:InvokeGenericMethod(o,

                                                                                        "HandlePayment",

                                                                                       "Verpigo.Extensibility.ExtensionManager"),

      PaymentExtension_Adyen.AdyenPaymentHandlerExtension) .

 
 

Posted by DenDuze on 04-Oct-2018 07:00

Arrrrh, damn how stupid.

Changed it but I get

Invalid handle.  Not initialized or points to deleted object (3135)

I also tried with

o2 = CAST (ReflectionHelper:InvokeGenericMethod( o,

                                                "Invoke",

                                                "Verpigo.Extensibility.ExtensionManager"),

                                                PaymentExtension_Adyen.AdyenPaymentHandlerExtension).

But then I get

System.Reflection.TargetParameterCountException: Parameter count mismatch.

Like I already mentioned it's not clear to me what the original code just does:

ExtensionManager.Instance.Invoke(Of IPaymentHandlerExtension)(Sub(x) x.HandlePayment(paymentId, amount, comment)).

Maybe someone can explain me what this code just does because I tried multiple things but always get some kind of error

The Invoke methos in ExtensionManager.vb:

Public Sub Invoke(Of T)(act As Action(Of T))

       For Each extension As IExtension In _extensions.Where(Function(e) GetType(t).IsAssignableFrom(e.GetType))

           Dim extOfT = DirectCast(extension, T)

           act(extOfT)

       Next

   End Sub

The HandlePayment method in AdyenPaymentHandlerExtension;vb:

Public Function HandlePayment(paymentMethodId As Integer, amount As Single, comment As String) As Boolean Implements IPaymentHandlerExtension.HandlePayment

       'only handle the payment codes that are configured in the config file

       If Not AcceptedPaymentMethodIds.Contains(paymentMethodId) Then

       Return False

       End If

       Parameters = New List(Of String) From {"-a", amount.ToString(CultureInfo.InvariantCulture), "-c", comment}

       Return RunProcess() = 0 'external process has to return 0 if everything is OK

   End Function

So I really have no idea it that is translatable  to Progress or not (and how)

Posted by Mike Fechner on 04-Oct-2018 08:07

Is o initialized  ?

Posted by DenDuze on 04-Oct-2018 08:15

I guess it is,

I did:

def var o as Verpigo.Extensibility.ExtensionManager.

Verpigo.Extensibility.ExtensionManager:Init("C:\Users\didier.d\Desktop\test_angloParts").

o = Verpigo.Extensibility.ExtensionManager:Instance.

When I do valid-object(o) I get true back so...

Regards

Didier

Posted by Mike Fechner on 04-Oct-2018 08:20

As I said before. VB.NET ... what I'd suggest is that you share the link to the API documentation of the classes you're trying to access.

Posted by jquerijero on 04-Oct-2018 12:02

Now understand, Invoke is actually trying to call HandlePayment on all available matching extensions. I don't think this is translatable to ABL. The code I posted will not work; it's for a different purpose.

Specially this line will not translate:
ExtensionManager.Instance.Invoke(Of IPaymentHandlerExtension)(Sub(x) x.HandlePayment(paymentId, amount, comment)) because Sub(x) x.HandlePayment(paymentId, amount, comment) is an inline delegate definition.

The key is re-implementing Invoke to not use delegate. Basically, Invoke should look something like this;

Invoke(paymentId, amount, comment)
... You might need to iterate through all the extension and see which extension implements HandlePayment by checking if TYPE-OF is IPaymentHandlerExtension.

Posted by DenDuze on 05-Oct-2018 01:13

@Mike: As far as I know there is no documentation available.

It's a combination of a c#-project written by some guy (doesn't work there anymore) and a vb-project written by another programmer (also doesn't work there anymore) where another programmer makes a call to from on another vb-project (as far as I understand).

The latter programmer still works there but only knows that his code makes everything work fine for the last # years.

Now they want to change to our software but still want to keep using this functionality.

The easiest way to do that is by trying to translate the code of the latest vb-project (it's only a few lines) to Progress code because if we hare to re-write the whole functionality ....

Maybe you can spare some time in Dublin to take a look @this (ofcourse with some drinks nearby)

@jquerijero: I'm not sure I completely understand but what I do not understand is why I can not call that HandlePayment function directly. I also do not see how this code will make the whole thing work but ok if this worked in the past with the vb-code it should work with the Progress-code i guess.

Regards

Didier

Posted by Mike Fechner on 05-Oct-2018 01:20

So you’re translating VB.NET code calling into C# classes.
 
Do you have the source code of the C# classes available?
 
Maybe we should offer you a few hours of consultancy to get that working?

Posted by DenDuze on 05-Oct-2018 01:40

As far as i understand it's like that.

Now thanks for the offer, I also contacted that latest vb-programmer and asked him if he can make  some class that does everything that is needded and that I just can instantiate.

I will wait on that answer before I will proceed to contact our managament about your consultancy

Posted by jquerijero on 05-Oct-2018 15:30

[quote user="DenDuze"]I'm not sure I completely understand but what I do not understand is why I can not call that HandlePayment function directly. [/quote]

You should be able to if you can get the extension instance.

The problem you are facing, as I understand it, is that the extensions are loading dynamically. My suggestion is actually iterating through the dynamic instances and then check the instance type. You can save the dynamically created extension instances to a temp-table or a generic collection. While iterating, if the instance type matches iPaymentHandleExtension using TYPE-OF, then you can certainly just call HandlePayment directly using CAST. This code can replace the call to Invoke.

This thread is closed