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);
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 am working with the original MMO that ever opened called VZones and they have a dll file that allows you to call the functions from this dll to do certain things within the program.
I have found some VB.NET code and the problem I am having is converting it to a way that will work with C# (using VS 2017)
You setup the DLL calls with this, which works fine:
[DllImport("vzdapi.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern string DapiGetText(string BufferIn, int LengthIn, int Timeout);
The problem is I need to convert this VB.NET code that is from someone else to what will work in C#. I have tried a few different options but the program just closes and never gives me an error.
object obj1 = (object)new string(char.MinValue, 32678);
vzText.Text = this.DapiGetText(Conversions.ToString(obj1), Strings.Len(RuntimeHelpers.GetObjectValue(obj1)), 1500);
The problem arises in the Conversions.ToString part, which I have of course tried to just make obj1.ToString() and that may work fine but the place I think is getting caught up is when it tries to run the middle code "Strings.Len(RuntimeHelpers.GetObjectValue(obj1))".
Does anyone have any help into getting this into something that will work in C#? Thanks!
I'm wondering if the conversions are necessary as the initial object you define is already a string, try the following solution:
string obj = new string(char.MinValue, Int16.MaxValue);
vzText.Text = this.DapiGetText(obj, obj.Length, 1500);
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.
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);
}
First, I know that it doesn't make sense to compare the dllimport attribute and the getProcAddress function directly. Rather, I am interested in comparing two pieces of code, that achieve basically the same thing - calling a function in a dll - by either importing the function with the dllimport attribute or with the getProcAddress function. Specifically, I am writing a C# application that uses some function in a dll that I have written. At first I accessed my dll function with the following piece of code:
class DllAccess
{
[DllImport("kernel32.dll", SetLastError = true)]
private extern IntPtr LoadLibrary(String DllName);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate Bool BarType(Byte arg); // return value indicates whether function call went well or not.
Bool Bar(Byte arg)
{
Bool ok = false;
IntPtr pDll= LoadLibrary("foo.dll");
if (pDll != IntPtr.Zero)
{
IntPtr pfunc = GetProcAddress(pDll, "bar");
if (pFunc != IntPtr.Zero)
{
BarType bar = (BarType)Marshal.GetDelegateForFunctionPointer(pFunc, typeof(BarType));
ok = bar(arg);
}
FreeLibrary(pDll);
}
return ok;
}
}
However, I later needed to get at the lastError value, if it had been set during the dll call, so I changed my code into this:
class DllAccess
{
[DllImport("foo.dll", EntryPoint = "bar", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private extern Bool DllBar(Byte arg); // return value indicates whether function call went well or not.
Bool Bar(Byte arg)
{
return DllBar(arg);
}
}
This is of course much tidier, and as mentioned, it sets the lastError code. Obviously, my first piece of code gives me the possibility of changing dll and function call at runtime, but at the moment this is not required. So my question is: Are there any reasons for using the first formulation, if I am certain, that I will not be using another dll or another function?
The only real advantages of using GetProcAddress are that you can unload the DLL manually as well as call a function, and that you can change the naming easily at runtime.
However, the second option provides you with a huge number of benefits. In addition to being "tidier", it also handles much of the marshaling of data types for you - which becomes very important with certain APIs.
That being said, if you do the method you have listed as first, you should make sure to unload everything, as well. Right now, you're basically leaking addresses each time you call Bar()... For details, look at FreeLibrary.
Probably the biggest advantage of GetProcAddress is that it lets you control the search path of the DLL. For example, you could load either 32-bit or 64-bit version of a native DLL automatically. With DllImportAttribute, this isn't possible.