Page MenuHomePhabricator

Unhandled Exception with custom widget class
Open, HighPublic

Description

I tried to create Mybutton Class inherited from EFl.Ui.Button Class. but it doesn't work.
Sample code:

//mcs my_button.cs `pkg-config --libs efl-mono`
using System;
using Efl.Ui;

public class Mybutton : Efl.Ui.Button
{
    public Mybutton(Efl.Object parent, System.String style = null) :
        base(parent, style) {}
}

public class Example : Efl.Csharp.Application
{
    protected override void OnInitialize(Eina.Array<System.String> args)
    {
        Efl.Ui.Win win = new Efl.Ui.Win(null);
        win.SetWinType(Efl.Ui.WinType.Basic);
        win.SetText("Container demo");
        win.SetAutohide(true);
        win.VisibilityChangedEvt += (object sender, Efl.Gfx.IEntityVisibilityChangedEvt_Args e) => {
          if (e.arg == false)
              Efl.Ui.Config.Exit();
        };
        win.SetSize(new Eina.Size2D(350,250));

        Mybutton btn = new Mybutton(win);

        win.SetContent(btn);
    }
    public static void Main()
    {
        var example = new Example();
        example.Launch();
    }
}

Error message:

WRN<29394>:mono /home/yohoho/efl/core/efl/src/lib/evas/canvas/efl_canvas_object.eo.cs:4180 visible_set() Callback error: System.InvalidOperationException: Could not find the C# binding class for the EFL class: Efl.Ui.Focus.IParentProvider
  at Efl.Eo.ClassRegister.GetManagedType (System.IntPtr klass) [0x0011f] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Eo.MarshalEflClass.MarshalNativeToManaged (System.IntPtr pNativeData) [0x0002b] in <3209824ed5cc4357ba317101d56f9de8>:0
  at (wrapper native-to-managed) Efl.ObjectNativeInherit.provider_find(intptr,intptr,System.Type)
  at (wrapper managed-to-native) System.Object.wrapper_native_0x7ff325e9a2c2(intptr,bool)
  at Efl.Canvas.Object.SetVisible (System.Boolean v) [0x00036] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Canvas.ObjectNativeInherit.visible_set (System.IntPtr obj, System.IntPtr pd, System.Boolean v) [0x00026] in <3209824ed5cc4357ba317101d56f9de8>:0
DBG<29394>:mono /home/yohoho/efl/core/efl/src/bindings/mono/eo_mono/iwrapper.cs:699 GetInstance() MarshalTest.GetInstace cookie
ERR<29394>:mono /home/yohoho/efl/core/efl/src/lib/ecore/efl_loop.eo.cs:246 on_ArgumentsEvt_NativeCallback() Efl.EflException: Unhandled C# exception occurred.
  at Eina.Error.Raise (Eina.Error e) [0x00016] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Eina.Error.RaiseIfUnhandledException () [0x00020] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Ui.Win.SetContent (Efl.Gfx.IEntity content) [0x0003d] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Example.OnInitialize (Eina.Array`1[T] args) [0x0006c] in <0a75eabb50d34425ae0d2e489a4ee980>:0
  at Efl.Csharp.Application.<Launch>m__0 (System.Object sender, Efl.LoopArgumentsEvt_Args evt) [0x0001a] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Loop.On_ArgumentsEvt (Efl.LoopArgumentsEvt_Args e) [0x0003e] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Loop.on_ArgumentsEvt_NativeCallback (System.IntPtr data, Efl.Event+NativeStruct& evt) [0x00017] in <3209824ed5cc4357ba317101d56f9de8>:0
## Copy & Paste the below (until EOF) into a terminal, then hit Enter

eina_btlog << EOF
/usr/lib/libeina.so.1    0x7ff326128474 0x7ff3260f4000
/usr/lib/libeina.so.1    0x7ff3261274cf 0x7ff3260f4000
/usr/lib/libeina.so.1    0x7ff326128e1e 0x7ff3260f4000
??       -
EOF

DBG<29394>:mono /home/yohoho/efl/core/efl/src/lib/evas/canvas/efl_canvas_object.eo.cs:4148 visible_get() function efl_gfx_entity_visible_get was called
WRN<29394>:mono /home/yohoho/efl/core/efl/src/lib/evas/canvas/efl_canvas_object.eo.cs:4155 visible_get() Callback error: Efl.EflException: Unhandled C# exception occurred.
  at Eina.Error.Raise (Eina.Error e) [0x00016] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Eina.Error.RaiseIfUnhandledException () [0x00020] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Canvas.Object.GetVisible () [0x0003c] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Canvas.ObjectNativeInherit.visible_get (System.IntPtr obj, System.IntPtr pd) [0x00028] in <3209824ed5cc4357ba317101d56f9de8>:0
DBG<29394>:mono /home/yohoho/efl/core/efl/src/lib/elementary/efl_ui_widget.eo.cs:2932 widget_parent_get() function efl_ui_widget_parent_get was called
DBG<29394>:mono /home/yohoho/efl/core/efl/src/bindings/mono/eo_mono/iwrapper.cs:699 GetInstance() MarshalTest.GetInstace cookie
DBG<29394>:mono /home/yohoho/efl/core/efl/src/bindings/mono/eo_mono/iwrapper.cs:732 MarshalNativeToManaged() MarshalTest.MarshalNativeToManaged
WRN<29394>:mono /home/yohoho/efl/core/efl/src/lib/elementary/efl_ui_widget.eo.cs:2939 widget_parent_get() Callback error: Efl.EflException: Unhandled C# exception occurred.
  at Eina.Error.Raise (Eina.Error e) [0x00016] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Eina.Error.RaiseIfUnhandledException () [0x00020] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Ui.Widget.GetWidgetParent () [0x0003c] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Ui.WidgetNativeInherit.widget_parent_get (System.IntPtr obj, System.IntPtr pd) [0x00028] in <3209824ed5cc4357ba317101d56f9de8>:0
DBG<29394>:mono /home/yohoho/efl/core/efl/src/lib/elementary/efl_ui_widget.eo.cs:3425 focus_state_apply() function efl_ui_widget_focus_state_apply was called
WRN<29394>:mono /home/yohoho/efl/core/efl/src/lib/elementary/efl_ui_widget.eo.cs:3434 focus_state_apply() Callback error: Efl.EflException: Unhandled C# exception occurred.
  at Eina.Error.Raise (Eina.Error e) [0x00016] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Eina.Error.RaiseIfUnhandledException () [0x00020] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Ui.Widget.FocusStateApply (Efl.Ui.WidgetFocusState current_state, Efl.Ui.WidgetFocusState& configured_state, Efl.Ui.Widget redirect) [0x0004f] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Ui.WidgetNativeInherit.focus_state_apply (System.IntPtr obj, System.IntPtr pd, Efl.Ui.WidgetFocusState+NativeStruct current_state, Efl.Ui.WidgetFocusState+NativeStruct& configured_state, Efl.Ui.Widget redirect) [0x0003a] in <3209824ed5cc4357ba317101d56f9de8>:0

Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object
  at Efl.Ui.WidgetFocusState+NativeStruct.op_Implicit (Efl.Ui.WidgetFocusState _external_struct) [0x00008] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Ui.WidgetNativeInherit.focus_state_apply (System.IntPtr obj, System.IntPtr pd, Efl.Ui.WidgetFocusState+NativeStruct current_state, Efl.Ui.WidgetFocusState+NativeStruct& configured_state, Efl.Ui.Widget redirect) [0x00087] in <3209824ed5cc4357ba317101d56f9de8>:0
  at (wrapper native-to-managed) Efl.Ui.WidgetNativeInherit.focus_state_apply(intptr,intptr,Efl.Ui.WidgetFocusState/NativeStruct,Efl.Ui.WidgetFocusState/NativeStruct&,Efl.Ui.Widget)
  at (wrapper managed-to-native) System.Object.wrapper_native_0x7ff32698d630(intptr)
  at Efl.Loop.Begin () [0x00036] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Csharp.Application.Launch (Efl.Csharp.Components components) [0x00066] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Example.Main () [0x00006] in <0a75eabb50d34425ae0d2e489a4ee980>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
  at Efl.Ui.WidgetFocusState+NativeStruct.op_Implicit (Efl.Ui.WidgetFocusState _external_struct) [0x00008] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Ui.WidgetNativeInherit.focus_state_apply (System.IntPtr obj, System.IntPtr pd, Efl.Ui.WidgetFocusState+NativeStruct current_state, Efl.Ui.WidgetFocusState+NativeStruct& configured_state, Efl.Ui.Widget redirect) [0x00087] in <3209824ed5cc4357ba317101d56f9de8>:0
  at (wrapper native-to-managed) Efl.Ui.WidgetNativeInherit.focus_state_apply(intptr,intptr,Efl.Ui.WidgetFocusState/NativeStruct,Efl.Ui.WidgetFocusState/NativeStruct&,Efl.Ui.Widget)
  at (wrapper managed-to-native) System.Object.wrapper_native_0x7ff32698d630(intptr)
  at Efl.Loop.Begin () [0x00036] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Csharp.Application.Launch (Efl.Csharp.Components components) [0x00066] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Example.Main () [0x00006] in <0a75eabb50d34425ae0d2e489a4ee980>:0

Is there any method or property that i should override?

YOhoho created this task.Mar 29 2019, 1:52 AM
YOhoho triaged this task as High priority.
YOhoho updated the task description. (Show Details)Apr 2 2019, 6:54 PM
YOhoho added a comment.Apr 2 2019, 7:08 PM
WRN<29394>:mono /home/yohoho/efl/core/efl/src/lib/evas/canvas/efl_canvas_object.eo.cs:4180 visible_set() Callback error: System.InvalidOperationException: Could not find the C# binding class for the EFL class: Efl.Ui.Focus.IParentProvider
  at Efl.Eo.ClassRegister.GetManagedType (System.IntPtr klass) [0x0011f] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Eo.MarshalEflClass.MarshalNativeToManaged (System.IntPtr pNativeData) [0x0002b] in <3209824ed5cc4357ba317101d56f9de8>:0
  at (wrapper native-to-managed) Efl.ObjectNativeInherit.provider_find(intptr,intptr,System.Type)
  at (wrapper managed-to-native) System.Object.wrapper_native_0x7ff325e9a2c2(intptr,bool)
  at Efl.Canvas.Object.SetVisible (System.Boolean v) [0x00036] in <3209824ed5cc4357ba317101d56f9de8>:0
  at Efl.Canvas.ObjectNativeInherit.visible_set (System.IntPtr obj, System.IntPtr pd, System.Boolean v) [0x00026] in <3209824ed5cc4357ba317101d56f9de8>:0

The log said sample app is touching Efl.Ui.Focus.IParentProvider during Efl.ObjectNativeInherit.provider_find. however, Efl.Ui.Focus.IParentProvider class is not generated, becuase efl_ui_focus_parent_provider.eo is in elm_private_eolian_files. when i move some private eo files to public, that issue is fixed. but i guess it isn't proper solution.

The log said sample app is touching Efl.Ui.Focus.IParentProvider during Efl.ObjectNativeInherit.provider_find. however, Efl.Ui.Focus.IParentProvider class is not generated, becuase efl_ui_focus_parent_provider.eo is in elm_private_eolian_files. when i move some private eo files to public, that issue is fixed. but i guess it isn't proper solution.

Yeah. The issue is C code calling efl_find_provider on the C#-created Eo class. What happens is somewhat this:

  1. C calls efl_provider_find on the C#-class instance
  2. This instance's Eo_Class calls the C# delegate we passed as the apifunc when we created it.
  3. The parameters get marshaled to the corresponding C# type (e.g. Efl_Class to System.Type for klass)
  4. We call instance.FindProvider(klass) to call an eventual C# override.
    1. If it is not overridden by C#, automatically fallback to the C implementation as if it was called on a generated class.

So, the problem is in point 3.

And the core question becomes: what should we pass to someone who overrides FindProvider when a private Eo type is passed as parameter?

Maybe we could generate the private Eo classes but instead of complete classes with methods, events, etc, we generate "almost opaque" ones, storing just the EoId and the EoClass for them. This would allow them to be passed around as parameters while not exposing too much.

PS: Adding xavi and vitor to the discussion.

bu5hm4n added a subscriber: bu5hm4n.Apr 3 2019, 1:51 AM

I think we can even declare Efl.Ui.Focus.Parent_Provider stable and just have this one function in it beta, this should be okayish. If we don't use this one day, then it will just be a empty interface which is not used at all, no harm at all (i think)

What does this problem have to do with betaness? The app is using Efl.Ui.Button so it is using Beta features already, no?

@lauromoura : So what is the problem, that params are marshalled to C# to be passed to a possible C# override, but if the override does not exist they are then sent to the C fallback, which was expecting C params?
Or is the problem that "private EO types" are not currently being exposed to C#? What is a "private EO type"?
I thought that, from the moment we understood that C# should be usable to extend ANY EFL class, absolutely all EFL types should be available to C#.

@lauromoura : So what is the problem, that params are marshalled to C# to be passed to a possible C# override, but if the override does not exist they are then sent to the C fallback, which was expecting C params?
Or is the problem that "private EO types" are not currently being exposed to C#? What is a "private EO type"?

It's a mix of those.

Currently for C#-derived classes all Eo method calls do this round trip call through C# and the types are marshaled. For the case of private types, the marshaling fails and breaks the method call.

In a future optimization, we could try to avoid this round trip if the C# class does not implement the method (not sure if easily achieved). But the private types are indeed an issue as they can be passed around as valid parameters.

I thought that, from the moment we understood that C# should be usable to extend ANY EFL class, absolutely all EFL types should be available to C#.

Not actually fully available to C# - we may want stuff to be actually used only in C - but at least visible enough so it can be passed as parameters and forwarded back to C.

If these params come from C and go to C undisturbed, won't an IntPtr be enough?

What is the problematic type in the example that @YOhoho provides?

If these params come from C and go to C undisturbed, won't an IntPtr be enough?

This could happen if we only add wrappers to actually overriden Eo methods in the newly created Eo class. We could add a task to evaluate this after the release.

What is the problematic type in the example that @YOhoho provides?

The Efl.Ui.Focus_Parent interface is private, so C# bindings can't find a corresponding C# type and fails the FindProvider call, seemingly messing up things in a chain reaction when the call gets back to C.

After talking with @bu5hm4n on IRC I understood what you mean by "private". I was not aware that not all .eo files are compiled in C# because of the priv_eo_files rule in meson.
Well, if those classes are needed in C#, then I agree with @bu5hm4n we could make them public, but still @beta so nobody uses them.

The stack below fixes this instance of the FindProvider problem by making sure only C#-overriden methods are called from C. The proper way to handle private classes will be dealt with in T7789 and related tasks.

D8579 - Add override interceptors only for actually C#-overriden methods
D8580 - Return C# null when a null pointer is given from C