Nick H
Nick H

Reputation: 51

Embedding Julia in C# - passing and returning arguments

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

Answers (1)

pm100
pm100

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

Related Questions