GtkExtra Marshaling in C# Mono(Linux)



  • Hallo,

    ich versuche gerade die GtkExtra in Mono/C# zu portieren.

    Zumindest finde ich in Google dazu nichts. Prinzipiell sollte es gehen, aber meine Kenntnisse reichen da leider nicht aus. Hoffe es kann jemand dabei helfen, zumindest die grundlegende Techniken aufzuzeigen.

    Die erste Anlaufstelle ist Mono-Project mit Interop with Native Libraries.

    Habe installiert:

    libgtkextra-3.0
    libgtkextra-3.0-doc
    libgtkextra-dev
    

    Mehr gibt es dazu nicht (außer Source-Code, brauch ich aber erst mal nicht).

    System Linux, Debian, AMD64.

    Mein Code:

    namespace GtkExtraHelper
    {
    	using Gtk;
    	using System;
    	using System.Runtime.InteropServices;
    
    	public static class GtkExtra
    	{
    		[DllImport("libgtkextra.so")]
    		public static extern Gtk.Widget gtk_sheet_new(uint row, uint column, string title);
    	}
    }
    

    Zu portieren wäre die Funktion:

    GtkWidget *gtk_sheet_new(guint rows, guint columns, const gchar *title);
    

    Das Problem geht schon mal los mit GktWidget*. Das muss man wahrscheinlich erst mal bekannt machen, glaube ich. Einfach mit Gtk.Widget funktioniert schon mal nicht.

    Eine Frage habe ich jetzt: ist es der richtige Weg, den ich so eingeschlagen habe, oder fehlt da noch was?

    Ich denke es ist kein Problem für jemanden, der sich damit auskennt.

    Vielen Dank schon mal im Voraus!



  • Solange du nur die Adresse als solches in C# benötigst (um diese an andere Funktionen der Lib weiterzureichen), kannst du einfach

    IntPtr
    

    dafür nehmen.



  • Das wäre zu leicht 😕

    namespace GtkExtraHelper
    {
    	using Gtk;
    	using System;
    
    	public class MainWindow : Gtk.Window
    	{
    		public MainWindow() : base("GtkExtra-Helper")
    		{
    			var sw = new ScrolledWindow(null, null);
    			var vb = new VBox(false, 0);
    
    			vb.PackStart(sw);
    
    			var sheet = GtkExtra.gtk_sheet_new(2, 2, "Test");
    
    			sw.Add((Gtk.Widget)sheet);
    
    			Add(vb);
    			ShowAll();
    		}
    	}
    }
    

    Fehler



  • Ein kurzer Blick auf Gtk.Widget in Assembly-Browser.



  • Wenn ich das richtig sehe, gibt es doch einen Widget-Konstruktor mit IntPtr als Parameter:

    var sheet = GtkExtra.gtk_sheet_new(2, 2, "Test");
    
    var widget = new Gtk.Widget(sheet);
    sw.Add(widget);
    


  • Geil 👍

    Guter Hinweiß, Super danke!

    Den Einstieg schon mal geschafft.

    Bild



  • Ok, weiter geht's 🙂

    Es war schon fast zu einfach. Habe jetzt folgenden Code zusammen "gebastelt"

    namespace GtkExtraHelper
    {
    	using Gtk;
    	using System;
    	using System.Runtime.InteropServices;
    
    	public static class GtkExtra
    	{
    		[DllImport("libgtkextra-x11-3.0.so")]
    		public static extern IntPtr gtk_sheet_new(uint rows, uint columns, string title);
    
    		[ComVisible(true)]
    		[Serializable]
    		public delegate int CellActivateEventHandler(IntPtr sheet, int row, int col, IntPtr data);
    	}
    }
    

    Einen extra GtkSheet:

    namespace GtkExtraHelper
    {
    	using GLib;
    	using Gtk;
    	using System;
    
    	public class GtkSheet : Gtk.Widget
    	{
    		public GtkSheet(uint rows, uint columns, string title)
    			: base(GtkExtra.gtk_sheet_new(rows, columns, title))
    		{
    		}
    
    		[Signal("activate")]
    		public event GtkExtra.CellActivateEventHandler Cell_Activate
    		{
    			add {
    				var signal = Signal.Lookup(this, "activate");
    				signal.AddDelegate(value);
    			}
    
    			remove {
    				var signal = Signal.Lookup(this, "activate");
    				signal.RemoveDelegate(value);
    			}
    		}
    	}
    }
    

    Und MainWindow:

    namespace GtkExtraHelper
    {
    	using Gtk;
    	using System;
    
    	public class MainWindow : Gtk.Window
    	{
    		public MainWindow() : base("GtkExtra-Helper")
    		{
    			SetDefaultSize(600, 480);
    
    			var vb = new VBox(false, 0);
    			var sw = new ScrolledWindow(null, null);
    
    			vb.PackStart(sw);
    
    			var sheet = new GtkSheet(20, 20, "Sheet");
    
    			sheet.Cell_Activate += HandleCell_Activate;
    
    			sw.Add(sheet);
    
    			Add(vb);
    
    			ShowAll();
    		}
    
    		int HandleCell_Activate (IntPtr sheet, int row, int col, IntPtr data )
    		{
    			return 0;
    		}
    
    	}
    }
    

    Damit versuche ich ein EventHandler umzusetzen laut Tutorial.

    Ich habe es mit einem EventHandler von Gtk versucht, es hat geklappt aber ich bekomme keine Daten. Und hier bekomme ich eine Exception geworfen, die ich leider nicht nachvollziehen kann. Jedenfalls stimmt was nicht an den Parametern. Kann jemand weiter helfen? Vielen Dank!

    $ mono ./GtkExtraHelper.exe                                                                  
    Marshaling activate signal                                                                                                                     
    Exception in Gtk# callback delegate                                                                                                            
      Note: Applications can use GLib.ExceptionManager.UnhandledException to handle the exception.
    System.Reflection.TargetParameterCountException: Number of parameter does not match expected count.
      at System.Reflection.Binder.ConvertValues (System.Object[] args, System.Reflection.ParameterInfo[] pinfo, System.Globalization.CultureInfo culture, Boolean exactMatch) [0x00000] in <filename unknown>:0 
      at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0 
      at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <filename unknown>:0 
      at System.Delegate.DynamicInvokeImpl (System.Object[] args) [0x00000] in <filename unknown>:0 
      at System.MulticastDelegate.DynamicInvokeImpl (System.Object[] args) [0x00000] in <filename unknown>:0 
      at System.Delegate.DynamicInvoke (System.Object[] args) [0x00000] in <filename unknown>:0 
      at GLib.Signal.ClosureInvokedCB (System.Object o, GLib.ClosureInvokedArgs args) [0x00000] in <filename unknown>:0 
      at GLib.SignalClosure.Invoke (GLib.ClosureInvokedArgs args) [0x00000] in <filename unknown>:0 
      at GLib.SignalClosure.MarshalCallback (IntPtr raw_closure, IntPtr return_val, UInt32 n_param_vals, IntPtr param_values, IntPtr invocation_hint, IntPtr marshal_data) [0x00000] in <filename unknown>:0 
       at GLib.ExceptionManager.RaiseUnhandledException(System.Exception e, Boolean is_terminal)
       at GLib.SignalClosure.MarshalCallback(IntPtr raw_closure, IntPtr return_val, UInt32 n_param_vals, IntPtr param_values, IntPtr invocation_hint, IntPtr marshal_data)
       at Gtk.Widget.gtk_widget_show_all(IntPtr )
       at Gtk.Widget.ShowAll()
       at GtkExtraHelper.MainWindow..ctor()
       at GtkExtraHelper.MainClass.Main(System.String[] args
    


  • Ich glaube es liegt an [Serializable]-Parameter. Kann ich jetzt aber leider überhaupt nicht nachvollziehen, wie es zusammengebaut ist.

    Kann man das anders definieren? Auf die Parameter der C-Funktion abgestimmt, wie mache ich das?



  • Mach mal deine Ereignismethode statisch:

    static int HandleCell_Activate (IntPtr sheet, int row, int col, IntPtr data)
    

    GTK kann nichts mit objektorientierten Methoden anfangen (sondern kennt nur Funktionen).



  • Das ist es leider nicht, derelbe Fehler.

    Hier ist Events-Handling von gtk-sharp implementiert. Ich muss GtkExtra quasi "dazu" schalten.

    Ich versuche gerade anhand von Assembler-Code einen neuen Event zu bauen.



  • Es klappt soweit mit eigenem Event:

    namespace GtkExtraHelper
    {
    	using Gtk;
    	using GLib;
    	using System;
    	using System.Runtime.InteropServices;
    
    	public static class GtkExtra
    	{
    		public class CellActivateEventArgs : SignalArgs
    		{
    			private IntPtr sheet;
    			private int row;
    			private int column;
    			private IntPtr data;
    
    			public CellActivateEventArgs()
    			{
    			}
    
    			public CellActivateEventArgs(IntPtr s, int r, int c, IntPtr d)
    			{
    				sheet = s;
    				row = r;
    				column = c;
    				data = d;
    			}
    
    			public IntPtr Sheet { get { return sheet; } }
    
    			public int Row { get { return row; } }
    
    			public int Column { get { return column; } }
    
    			public IntPtr Data { get { return data; } }
    		}
    
    		[ComVisible(true)]
    		[Serializable]
    		public delegate int CellActivateEventHandler(object sender,CellActivateEventArgs args);
    
    		[DllImport("libgtkextra-x11-3.0.so")]
    		public static extern IntPtr gtk_sheet_new(uint rows, uint columns, string title);
    	}
    }
    

    Aber ich bekomme keine Daten.

    Da fehlt leider noch was 😕



  • Neue Problem. Mein Event wird nicht angenommen, warum auch immer 🙄

    Fehler. Was mache ich falsch?

    Ein Beispiel eines Events. Von dort bekomme ich hoffentlich die Daten her.

    Der Code bis jetzt:

    public class EventCellActivate : Event
    		{
    			public IntPtr sheet {
    				get {
    					return System.IntPtr.Zero;
    				}
    			}
    
    			public int Row {
    				get {
    					return 1;
    				}
    			}
    
    			public int Column {
    				get {
    					return 1;
    				}
    			}
    
    			public EventCellActivate(IntPtr raw) : base(raw)
    			{
    			}
    		}
    
    		public class CellActivateEventArgs : SignalArgs
    		{
    			public EventCellActivate Event {
    				get {
    					return (EventCellActivate)base.Args [0];
    				}
    			}
    		}
    
    		[ComVisible(true)]
    		[Serializable]
    		public delegate int CellActivateEventHandler(object sender,CellActivateEventArgs args);
    


  • Falls jemand bis dahin weiter helfen kann, würde ich mich freuen.

    Ich versuche erst mal mit gtkmm das Problem zu lösen. Ist vielleicht nicht gerade der beste Weg, aber wenn's funktioniert, soll es mir auch recht sein.



  • Hat sich erledigt, es geht auch direkt einen Signal zu connecten. Problem gelöst

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate int ActivateCellFuncPtr(IntPtr sheet,int row,int col,IntPtr data);
    
    [DllImport("libgtk-x11-2.0.so")]
    public static extern ulong gtk_signal_connect_full(
    	IntPtr obj,
    	string name, 
    	[MarshalAs(UnmanagedType.FunctionPtr)] ActivateCellFuncPtr ac_func,
    	IntPtr unsupported,
    	IntPtr data, 
    	IntPtr destroy_func,
    	int object_signal,
    	int	after);
    

Anmelden zum Antworten