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
Related
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:
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.
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
Below is my code in c#...
here callback is too implemented in c# only.
i want a callback from c++ dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
class Program
{
// [DllImport("C:/Users/kool/Documents/Visual Studio 2010/Projects/DLL/Debug/DLL.dll", CallingConvention = CallingConvention.Cdecl)]
static void Main(string[] args)
{
function1(function2); // i want thia function2 to be fetched from ++ dll
}
public delegate void fPointer(); // point to every functions that it has void as return value and with no input parameter
public static void function1(fPointer ftr)
{
fPointer point = new fPointer(ftr);
point();
}
public static void function2()
{
Console.WriteLine("Bla");
}
}
i will createa a dLL from where i will send function2 to
function1(function2);
how can i implement it??
One way is exporting the C# assembly as a type library and using it from C++ as if it were a COM component.
Use TlbExp.exe in the Visual Studio command prompt to export the C# assembly as a type library. Then register the type library with RegAsm.exe. Then in the C++ code use the #import directive to import the type library. You can now use the C# classes from C++ as if they were COM classes.
For more detail see: http://msdn.microsoft.com/en-us/library/ms172270.aspx
Edit: Sorry, which is it that you want to do: use C++ from C#, or use C# from C++?
Either one is possible. The link above explains how to use C# from C++. This one explains how to use C++ from C#: http://msdn.microsoft.com/en-us/library/z6tx9dw3.aspx
You can send pointer to your managed .net function and call it from unmamaged code (callback).
Detail here http://habrahabr.ru/post/130690/ (use google to translate it from russian if needed, but you need to look at last two code example).
Also check your code calling - it should comply on both managed and unmanaged sides (use __stdcall in C-code and CallingConvention = CallingConvention.Cdecl in DllImport attribute).
I am having trouble with using P/Invoke for C#. Here is the function (written in C++) that I am trying to call from the .dll:
string
BeatTracker::getName() const
{
return "Tempo and Beat Tracker";
}
And here is my code for trying to call this function:
[DllImport("qm-vamp-plugins.dll",EntryPoint="BeatTracker")]
public static extern string getName();
public QMTempo()
{
Console.WriteLine(getName());
}
What seems to be wrong? I am getting a BadImageFormatException. And how can I know what is wrong in future references aside from the vague names the IDE is giving me? I am using Visual Studio 2008 by the way.
Also I am using (but not sure if right) EntryPoint, to let it know that I am using the getName function from the BeatTracker class (because there are also getName functions for other classes, which are included in the single .dll file)
Thanks!
This exception can be caused by a mismath between the .NET runtime proc architecture used and the imported dll one.
More precisely:
Do you use a 64bit Windows? The runtime will, by default, run in 64bit. If your C++ library was compiled targeting 32bit, you will get a BadFormatException upon library loading. The Same goes if your .NET app is running 32bit and your C++ library was compiled targeting x64.
If you can recompile the library, do it. Otherwise you can force the .NET runtime to use a specified architecture at compilation, but it will prevent it from running on the other architecture. It's your choice ;) When coding against .NET or java, we tend to forget what really happen under the hood.
[DllImport("qm-vamp-plugins.dll",EntryPoint="BeatTracker")]
The EntryPoint should be getName(), not BeatTracker which is a class!
But even then you cannot call that, because getName() is member function which cannot be callled without instance.
So I would suggest that define free functions in the DLL, and export them. You can use class internally, in the DLL. You can work with handle of classes.
Example,
DLL code:
typedef BeatTracker* PBeatTracker;
typedef PBeatTracker HBeatTracker;
//exported functions
HBeatTracker CreateBeatTracker()
{
return new BeatTracker();
}
void DeleteBeatTracker(HBeatTracker handle)
{
delete handle;
}
string getName(HBeatTracker handle)
{
return handle->getName();
}
C# Code:
[DllImport("qm-vamp-plugins.dll",EntryPoint="CreateBeatTracker")]
public static extern IntPtr CreateBeatTracker();
[DllImport("qm-vamp-plugins.dll",EntryPoint="DeleteBeatTracker")]
public static extern void DeleteBeatTracker(IntPtr);
[DllImport("qm-vamp-plugins.dll",EntryPoint="getName")]
public static extern string getName(IntPtr);
public QMTempo()
{
IntPtr handle = CreateBeatTracker();
Console.WriteLine(getName(handle));
DeleteBeatTracker(handle);
}