Invoke not working the same as in desktop

I’m working on a web version of my desktop application.
The last days I’m trying to get Invoke work in the web application but so far without any luck.
The invoke command is used in the constructor of a Class.

This is the code in Desktop.

Dim info As Introspection.TypeInfo
info = Introspection.GetType(Me)
Dim methods() As Introspection.MethodInfo 
methods = info.GetMethods

For q As Integer = methods.LastIndex DownTo 0
  Dim p As Introspection.MethodInfo = methods(q)
  
  #If DebugBuild Then
    DebugLog p.name
  #EndIf
  
  If p.Name = "Window" Or p.Name = "DesktopWindow" Then
    Dim w As DesktopWindow = p.Invoke(Self)
    ParentWindow = w
    mParent = (ParentWindow <> Nil)
    Exit For
    
  End If
  
Next

Here w contains information about the Container Control where the Class is part of that Container Control.

This is the code in Web.

Dim info As Introspection.TypeInfo
info = Introspection.GetType(Me)
Dim methods() As Introspection.MethodInfo 
methods = info.GetMethods

For q As Integer = methods.LastIndex DownTo 0
  Dim p As Introspection.MethodInfo = methods(q)
  
  #If DebugBuild Then
    DebugLog p.name
  #EndIf
  
  If p.Name = "Page" Or p.Name = "WebPage" Then
    Dim w As WebPage = p.Invoke(Self)
    ParentWebPage = w
    mParent = (ParentWebPage <> Nil)
    Exit For
    
  End If
  
Next

Here w is always Nil.

Is this a known problem or is it a bug or ???

Can you describe what you are trying to do?

1 Like

Later in another method I use the ParentWindow (ParentWebPage) to loop through all the controls on that container control to do certain actions.

For i As Integer = 0 To ParentWebPage.ControlCount - 1
  c = ParentWebPage.ControlAt(i)
  
  Select Case c
    
    // *****************************************************
  Case IsA C_TextField // Subclass of DesktopTextfield
    // -----------------------------------------------------
    Select Case actiontype
    Case 1 // Populate
      C_TextField(c).InC = Me
      C_TextField(c).Dat = d.lookup(C_TextField(c).RsFieldName, "")
      C_TextField(c).MaximumCharactersAllowed = DbMain.DbFieldLength(Data.TableName, C_TextField(c).RsFieldName)
    Case 2 // Cancel
      C_TextField(c).Dat = d.lookup(C_TextField(c).RsFieldName, "")
    Case 3 // Validate - Only on 'Required'
      C_TextField(c).Validate
    Case 4 // Update db
      d.value(C_TextField(c).RsFieldName) = C_TextField(c).Dat.ReplaceAll("'", "''")
    End Select
    // *****************************************************
    Case ... // Other subclassed controls
    Case ... // Other subclassed controls
    ...
  End Select
Next i

If I’m reading your code correctly, you are checking some object (self - not clear what this is) and looking at all of its methods using Introspection, and then looking for a method with the name “Window” or “DesktopWindow” and then calling that method, and returning the value.

If I’ve described it correctly - no idea what that’s supposed to accomplish. :slight_smile:

Also, I’m not sure if it’s legal to have a Class that has a Method with the same name as the Class - in the olden days of REALbasic, that would be the Constructor method. Now Constructors are called Constructor.

Can you say more about this code?

Ok this is weird, if I run this code in the debugger in a DesktopWindow:

Event DesktopWindow1.Open
  Dim info As Introspection.TypeInfo
  info = Introspection.GetType(Me)
  Dim methods() As Introspection.MethodInfo  
  methods = info.GetMethods

  For q As Integer = methods.LastIndex DownTo 0
    Dim p As Introspection.MethodInfo = methods(q)
  
    If p.Name = "Window" Or p.Name = "DesktopWindow" Then
      // set breakpoint on next line
      Dim w As DesktopWindow = p.Invoke(Self) // <-- this raises Window.Open() again
      Exit For
    End If
  Next
end event

I get a stack overflow.

It appears that the DesktopWindow class does have a method named “Window” but when that is called (using p.invoke) it is actually calling the DesktopWindow.Open event, which then runs the code again, and again, eventually overflowing the stack.

I wonder if you are relying on some hidden, undocumented feature of DesktopWindow that doesn’t exist on WebPage?

The Class is called “cls_In_Control”
The method in “cls_In_Control” that uses the Invoke command is called “Constructor”
And the method that uses the ParentWindow is called “LoopControls” and is also a Method in “cls_In_Control”.

I don’t see any Method that has the same name as the Class.

Still not clear at all to me.

Backing up a bit - why are you using Introspection at all? Introspection is kind of a hack, and most of the time there’s a better way to do it. True, there are some cases where introspection is the only way to accomplish something, but that tends to be like 1% of the cases.

In other words: what are you trying to accomplish where you decided that Introspection was the right answer?

This is a general class that is added to a container control with various controls (textfields, checkboxes, etc.).

The class adds labels to the controls and is used to fill the data from the database in the controls and insert/update/delete the database data.
(This desktop class is made by Joost Rongen and I’m trying to convert this class to a web version.)

My problem is that I’m not clear what Class you are calling this code for. You said earlier:

But that’s not specific enough, and I was assuming you were calling this on a Window class.

I’m now thinking that this code is being called on instances of Control classes. Is that right?

If it is, then this code is just a really complicated way of doing something simple.

Instead of doing this:

Public Function getWindowFromControl(c as DesktopUIControl) As DesktopWindow
  dim w as DesktopWindow = c.window 
  return w
End Function

You have this overly complicated method that does the same thing, only using Introspection:

Public Function getWindowFromControlUsingIntrospection(c as DesktopUIControl) As DesktopWindow
  Dim info As Introspection.TypeInfo
  info = Introspection.GetType(c)
  Dim methods() As Introspection.MethodInfo 
  methods = info.GetMethods
  
  For q As Integer = methods.LastIndex DownTo 0
    Dim p As Introspection.MethodInfo = methods(q)
    
    #If DebugBuild Then
      DebugLog p.name
    #EndIf
    
    If p.Name = "Window" Or p.Name = "DesktopWindow" Then
      Dim w As DesktopWindow = p.Invoke(Self)
      return w
    End If
    
  Next

End Function

Am I getting closer to what’s going on?

1 Like

I think I see what’s going on.

First, I think there’s no reason to use Introspection for this - it’s overly complicated and easy to break things.

If you are going to use Introspection, it has to be done properly.

  • You need to be looking for a Property named “Window”.
  • However, your code is looking for a Method named “Window”, which fails.

This code works:

Public Function getWindowFromControlUsingIntrospection(c as DesktopUIControl) As DesktopWindow
  Dim info As Introspection.TypeInfo  
  info = Introspection.GetType(c)
  dim properties() as Introspection.PropertyInfo = info.GetProperties
  
  system.DebugLog "Scanning " + info.name + " properties"
  for each p as Introspection.PropertyInfo in properties
    #If DebugBuild Then
      system.DebugLog  "  " + p.name
    #EndIf
    If p.Name = "Window" Or p.Name = "DesktopWindow" Then
      Dim w As DesktopWindow = p.Value(c)
      return w
    End If
  Next
  return nil
End Function

Again, this is bad code, don’t use it.

If you want to get a control’s parent, you just use control.Window (for Desktop apps) or control.Page for Web apps.

1 Like

@Mike_D
First I tried control.Window and then I tried the getWindowFromControlUsingIntrospection.
When used in the Constructor method the result was still Nil.
I solved the problem by adding the DesktopContainer/WebContainer as a parameter to the LoopControls method.
Now I don’t need Introspection at all.
Thank you for your solutions. It helped me a lot in solving my problem.

1 Like