I am trying to access the c libnotify from my c# code to use libnotify on my linux laptop with dotnet core.
But everytime there is a problem to get the values from the lib.
This is the problematic c code:
typedef struct _NotifyNotification NotifyNotification;
typedef struct _NotifyNotificationPrivate NotifyNotificationPrivate;
struct _NotifyNotification
{
/*< private >*/
GObject parent_object;
NotifyNotificationPrivate *priv;
};
struct _NotifyNotificationPrivate
{
guint32 id;
char *app_name;
char *summary;
char *body;
/* NULL to use icon data. Anything else to have server lookup icon */
char *icon_name;
/*
* -1 = use server default
* 0 = never timeout
* > 0 = Number of milliseconds before we timeout
*/
gint timeout;
GSList *actions;
GHashTable *action_map;
GHashTable *hints;
gboolean has_nondefault_actions;
gboolean updates_pending;
gulong proxy_signal_handler;
gint closed_reason;
};
NotifyNotification *
notify_notification_new (const char *summary,
const char *body,
const char *icon);
Now I created two structs in my c# code and an extern method:
[StructLayout(LayoutKind.Explicit)]
internal struct NotifyNotification
{
[FieldOffset(1)]
public NotifyNotificationPrivate priv;
}
[StructLayout(LayoutKind.Explicit)]
internal struct NotifyNotificationPrivate
{
[FieldOffset(0)]
public uint id;
[FieldOffset(1)]
public IntPtr app_name;
[FieldOffset(2)]
public IntPtr summary;
[FieldOffset(5)]
public int timeout;
}
[DllImport("libnotify.so.4", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr notify_notification_new([MarshalAs(UnmanagedType.LPStr)] string summary,
[MarshalAs(UnmanagedType.LPStr)] string body,
[MarshalAs(UnmanagedType.LPStr)] string icon);
With this code I cast everything to the structs:
NotifyNotification no = (NotifyNotification) Marshal.PtrToStructure(not, typeof(NotifyNotification));
Console.WriteLine(Marshal.PtrToStringAnsi(no.priv.summary));
The basics are working and I can call other functions from the libnotify with the pointer from the notify_notification_new-method. But in the last line, with the WriteLine, the debugger says:
The program '...dll' has exited with code 0 (0x00000000).
There is no exception and no error. Whats going wrong? It is a problem with dotnet core? Because it is still in beta?
How can I get the text from the properties app_name, summary, body??
Thank you very much in advance for your help.
[StructLayout(LayoutKind.Explicit)]
says "dear compiler, I know what I'm doing, just... deal with it". Unfortunately, you didn't know what you were doing.[FieldOffset]
takes the offset in bytes, not members.GObject, presumably, is a pointer type. That means it takes up either 4 bytes (x86) or 8 bytes (amd64). Since .NET Core for Linux is currently only supported on amd64, it's 8 bytes. (Unless it's some other primitive structure).
[FieldOffset(1)]
says "start reading 1 byte after the pointer".Your next problem comes in that in C the struct is declared to have two members, the second one being a pointer. Your C# struct says the second member is itself a struct.
So if the memory at the address pointed to by
notify_notification_new
looked likeYou read
Much better would be to use Sequential layout:
Then:
Edit: Though, the most predictable approach is to make a C library (or C++ with
extern "C"
declarations) which avoids copying/interpreting the structures altogether (it lets the C compiler take care of that):The matching C# declaration on that would be to have the function declared as returning
IntPtr
and to pass that still toMarshal.PtrToStringAnsi
; because if you declare it as returning astring
the GC will think it's supposed to clean up the memory when the string goes out of scope.