Reputation: 51
So I've been able to get the following code working fine in Visual Studio on Windows 10:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void jl_init(string julia_home_dir);
[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void jl_eval_string(string str);
static void Main(string[] args)
{
jl_init(@"C:\Julia-0.4.3\bin");
jl_eval_string("push!(LOAD_PATH, \"c:/development/tools and testing/\")");
jl_eval_string("using test");
jl_eval_string("TestFunc()");
Console.ReadLine();
}
}
}
And - this program is calling c:\development\tools and testing\test.jl which contains the following Julia code:
module test
println("Loading the Module")
export TestFunc, Func2
function TestFunc()
println("In the function")
end
function Func1()
println("This function returns 4")
return 4
end
end
And it writes the following to the console:
Loading the module
In the function
and then waits for input before exitting.
However, this uses the jl_eval_string function to call things, which is declared to return nothing. I would like to be able to use jl_get_function, and then call a particular function using the jl_call0 function, and then have the julia code return something back to me (and once I can get this working, then it would be nice to step forward to using jl_call1 to pass an argument - but one step at a time for now.) I think the problem is that these functions return/accept datatypes of jl_function_t and jl_value_t, which is not defined in C# for me?
Something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void jl_init(string julia_home_dir);
[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void jl_eval_string(string str);
[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern object jl_get_function(object m,string name);
[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern object jl_call0(object m);
static void Main(string[] args)
{
// Pass
jl_init(@"C:\Julia-0.4.3\bin");
jl_eval_string("push!(LOAD_PATH, \"c:/development/tools and testing/\")");
jl_eval_string("using test");
jl_eval_string("TestFunc()");
object funcptr = jl_get_function("test", "Func1");
object ans = jl_call0(funcptr);
Console.ReadLine();
}
}
}
When I run this program I get the following: Unhandled Exception: System.Runtime.InteropServices.MarshalDirectiveException: PInvoke restriction: cannot return variants. at ConsoleApplication1.Program.jl_get_function(Object m, String name) at ConsoleApplication1.Program.Main(String[] args)
For reference - these functions are discussed here
I'm quite new to C# and working with dlls, so there may be something obvious here to someone else...
Thanks!
Upvotes: 3
Views: 3067
Reputation: 50210
making a c# wrapper for a c library is a complex process. I can give a few hints but strongly suggest reading up on it.
THe pinvoke bible is adam nathans book http://www.amazon.com/NET-COM-Complete-Interoperability-Guide/dp/067232170X
But for a start - for opaque handles use IntPtr not object
[DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jl_get_function(IntPtr m,string name);
Upvotes: 1