How to P/Invoke os_log? - c#

What should the syntax be to call the MacOS' os_log from C# in a .NET Core console app?
Based on
https://developer.apple.com/documentation/os/os_log
and
How to use iOS OSLog with Xamarin?
and
https://opensource.apple.com/source/xnu/xnu-4903.221.2/libkern/os/log.h.auto.html
I was expecting something like this:
using System.Runtime.InteropServices;
namespace Foo
{
class Program
{
[DllImport("__Internal", EntryPoint = "os_log_create")]
private static extern IntPtr os_log_create(string subsystem, string category);
[DllImport("__Internal", EntryPoint = "os_log")]
private static extern void os_log(IntPtr log, string format, string message);
static void Main(string[] args)
{
IntPtr log = os_log_create("some.bundle.id", "SomeCategory");
os_log(log, "%s", "Test!");
}
}
}
However, when I try to run this on my Mac I get a System.DllNotFoundException that says Unable to load shared library '__Internal' or one of its dependencies... .
Any help with this issue or P/Invoke between C# and MacOS would be very helpful, thanks!

Macro os_log
In contrast to the os_log_create function, os_log is a macro, as already mentioned in the comments.
So if you would write in C:
os_log(log, "%{public}s", "Test!");
It would finally call a function named _os_log_impl, but the first parameter of that would be a pointer __dso_handle to which we don't have access from the managed side.
Possible Solution
But you don't have to do without the new logging system from Apple. One possibility is to create a dynamic library that provides a defined API that can easily be called from the managed C# code.
How to Create a Dynamic Library in Xcode
It is easy to create a dynamic library in Xcode:
choose in XCode <File/New Project>
choose Library template in the macOS section
use Type Dynamic
Minimal Example
A minimal .c example for our own Logging library might look like this:
#include <os/log.h>
extern void Log(os_log_t log, char *message) {
os_log(log, "%{public}s", message);
}
Calling from .Net
I took your source and only slightly modified it:
using System;
using System.Runtime.InteropServices;
namespace Foo
{
class Program
{
[DllImport("System", EntryPoint = "os_log_create")]
private static extern IntPtr os_log_create(string subsystem, string category);
[DllImport("Logging", EntryPoint = "Log")]
private static extern void Log(IntPtr log, string msg);
static void Main(string[] args)
{
IntPtr log = os_log_create("some.bundle.id", "SomeCategory");
Log(log, "Test!");
}
}
}
The dynamic library created with Xcode has the name Logging. Our in C created logging function is named Log here.
Of course you can design the API as comfortable as you want, this should be a minimal example that is as close to the question as possible.
Output in Console Utility
The output in the Console utility (if you filter for some.bundle.id) would look like this:

Related

Run compiled C# from exe

I am working on my own scripting language using C# and ANTLR, and I've been able to implement almost everything I wanted.
I know that one can't make a perfect language on themselves, so I wanna build in a way to import functions from C# scripts. For that, i've researched about DLLImport anc calling functions from that, but i just cant seem to get that to work.
I am currently stuck at an EntryPointNotFoundException, however, my system uses object instead of strictly defined types, which threw a PInvoke: cannot return variants exception.
Here's some code i tried:
Program.cs
[DLLImport("mydll.dll", EntryPoint = "main", Charset = Charset.Unicode)]
static extern object main(object[] args)
main(Array.empty<object>())
C# class library used for creatng the dll
public class Test
{
public static object main(object[] args)
{
Console.WriteLine("Test sucessful!");
return 0;
}
}
Be forgiving if i am just overthinking this or don't know something obvious, I am still a pretty inexperienced developer.
For everyone who tries to acheive the same thing, here is the solution based on #PMF's comment:
var asm = Assembly.LoadFrom("YourDLL.dll");
var type = asm.GetType("YourNamespace.YourClass");
var method = type.GetMethod("YourMethod");
object[] args = new object[0];
method.Invoke(Activator.CreateInstance(type, Array.Empty<object>()), args);

Problems using methods from DLL - EntryPoints

I need to use a DLL created in C in a C # application. I have followed several ways seen on the internet and I can not use the methods that are supposed to be in the DLL.
When looking for the entrypoints I get 4, which are the following.
DllCanUnloadNow
llGetClassObject
DllRegisterServer
DllUnregisterServer
I'm trying with the following code:
[DllImport("DLL.dll", EntryPoint ="DllCanUnloadNow" ,CharSet = CharSet.Auto)]
public static extern int Open();
static void Main(string[] args)
{
Console.WriteLine(Open());
Console.ReadLine();
}
It doesn't matter what function I use, it returns always 0.
If I use a function called for example, asdf() I got 0.
Does anyone know how to use the DLL correctly? I think it's made as COM and I have a .lib file.
Thanks in advance.

Creating a CPP DLL for use in a C# program

So I have a WPF solution. I added a new project and added a CPP Dll project to it.
I used this example. Pretty straight forward.
http://www.codeproject.com/Articles/9826/How-to-create-a-DLL-library-in-C-and-then-use-it-w
Here is my code
CppTestDll.cpp
#include <stdio.h>
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf("Hello from DLL !\n");
}
}
When I build this I do in fact get a DLL
Now when I go into my WPF app and attempt to add a reference to this DLL I get this error.
"A reference to 'C:\DIR\testcppdll.dll' could not be added. Please
make sure that the file is accessible, and that it is a valid assembly
or COM component."
If you look in the example you cite:
Creating a simple C# application:
Start Visual Studio .NET. Go to File->New->Project.
Select Visual C#
Project. ... (you can select WPF Project)
Give the name to your application. Press OK. Into the specified
class, insert the following two lines:
[DllImport("TestLib.dll")]
public static extern void DisplayHelloFromDLL ();
In C#, keyword extern indicates that the method is implemented externally.
Your code should look something like this:
using System;
using System.Runtime.InteropServices; // DLL support
class HelloWorld
{
[DllImport("TestLib.dll")]
public static extern void DisplayHelloFromDLL ();
public void SomeFunction()
{
Console.WriteLine ("This is C# program");
DisplayHelloFromDLL ();
}
}
You don't add a reference to the to the DLL - you P/Invoke the Function using DLLImport

"Unable to find an entry point named" in c# using a C dll

I am trying a simple program to access a C function through a dll into a C# program,
class DllImportTest
{
[DllImport("TestApp.dll", EntryPoint = "main1")]
public static extern void main1();
}
class Program
{
static void Main(string[] args)
{
DllImportTest.main1() ;
}
I have seen through the code and the name of the function is the exactly right. I have also tried using Extern "C" but, it throws me an error as its .C file.
I have placed the .Dll in the C# executable folder.
Is there something that I am doing wrong here?
Found it!
I had to use Extern "C" coupled with __declspec(dllexport) . I had never used both together, Thanks guys

DllImport doesn't work as advertised in Mono (Linux, C#)

I'm getting to know Mono development in Linux, in baby steps. I'm trying to call Linux C libraries. This page, in theory, tells me how, but when I type the code below in MonoDevelop 2.2.2 (Fedora 13), I get a "Parsing Error (CS8025)" in "private static extern int getpid();". Moreover, the help system doesn't work.
using System;
using System.Runtime.InteropServices;
[DllImport("libc.so")]
private static extern int getpid();
namespace LinuxCaller
{
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ("Hello World!");
}
}
}
Function definitions cannot appear in the namespace scope in C#. This includes DLL import definitions. To fix this just move the function definition inside a type.
class MainClass {
[DllImport("libc.so")]
private static extern int getpid();
...
}
If you just need to access some common *nix system calls, check out the Mono.Unix namespace which provides wrappers around a lot of functions.
http://www.go-mono.com/docs/index.aspx?link=N%3aMono.Unix

Categories