-
Notifications
You must be signed in to change notification settings - Fork 126
Interop with C#
Wang Renxin edited this page Mar 11, 2016
·
58 revisions
This is a sample to represent how to interop MY-BASIC with C#. I assume you already know how to compile MY-BASIC to a shared library, we will need to specify the library name later. First of all we need to make a C# declaration as:
using System;
using System.Runtime.InteropServices;
using int_t = System.Int32;
using real_t = System.Single;
using bool_t = System.Int32;
namespace script
{
public static class my_basic
{
private const string LIB_NAME = "my_basic";
private const bool_t TRUE = 1;
private const bool_t FALSE = 0;
public const int MB_FUNC_OK = 0;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int mb_func_t(IntPtr s, ref IntPtr l);
[DllImport(LIB_NAME)]
public static extern int mb_init();
[DllImport(LIB_NAME)]
public static extern int mb_dispose();
[DllImport(LIB_NAME)]
public static extern int mb_open(out IntPtr s);
[DllImport(LIB_NAME)]
public static extern int mb_close(out IntPtr s);
[DllImport(LIB_NAME)]
public static extern int mb_reset(out IntPtr s, bool_t clrf = FALSE);
[DllImport(LIB_NAME)]
public static extern int mb_register_func(IntPtr s, string n, [MarshalAs(UnmanagedType.FunctionPtr)]mb_func_t f);
[DllImport(LIB_NAME)]
public static extern int mb_attempt_func_begin(IntPtr s, ref IntPtr l);
[DllImport(LIB_NAME)]
public static extern int mb_attempt_func_end(IntPtr s, ref IntPtr l);
[DllImport(LIB_NAME)]
public static extern int mb_attempt_open_bracket(IntPtr s, ref IntPtr l);
[DllImport(LIB_NAME)]
public static extern int mb_attempt_close_bracket(IntPtr s, ref IntPtr l);
[DllImport(LIB_NAME)]
public static extern int mb_has_arg(IntPtr s, ref IntPtr l);
[DllImport(LIB_NAME)]
public static extern int mb_pop_int(IntPtr s, ref IntPtr l, out int_t val);
[DllImport(LIB_NAME)]
public static extern int mb_pop_real(IntPtr s, ref IntPtr l, out real_t val);
[DllImport(LIB_NAME)]
public static extern int mb_pop_string(IntPtr s, ref IntPtr l, out string val);
[DllImport(LIB_NAME)]
public static extern int mb_pop_usertype(IntPtr s, ref IntPtr l, out IntPtr val);
[DllImport(LIB_NAME)]
public static extern int mb_push_int(IntPtr s, ref IntPtr l, int_t val);
[DllImport(LIB_NAME)]
public static extern int mb_push_real(IntPtr s, ref IntPtr l, real_t val);
[DllImport(LIB_NAME)]
public static extern int mb_push_usertype(IntPtr s, ref IntPtr l, IntPtr val);
[DllImport(LIB_NAME)]
public static extern int mb_load_string(IntPtr s, string l, bool_t reset = TRUE);
[DllImport(LIB_NAME)]
public static extern int mb_load_file(IntPtr s, string f);
[DllImport(LIB_NAME)]
public static extern int mb_run(IntPtr s);
}
}
Note this only a tutorial for the moment, so I didn't expose each API of MY-BASIC.
It's able to use MY-BASIC in C# with the declaration, considering we have a scripting interface for later invoking:
private int foo(System.IntPtr s, ref System.IntPtr l)
{
int x;
int y;
script.my_basic.mb_attempt_open_bracket(s, ref l);
script.my_basic.mb_pop_int(s, ref l, out x);
script.my_basic.mb_pop_int(s, ref l, out y);
script.my_basic.mb_attempt_close_bracket(s, ref l);
script.my_basic.mb_push_real(s, ref l, (float)x / y);
return script.my_basic.MB_FUNC_OK;
}
Try test it now:
System.IntPtr bas;
script.my_basic.mb_init();
script.my_basic.mb_open(out bas);
script.my_basic.mb_register_func(bas, "FOO", foo);
script.my_basic.mb_load_string(bas, "print foo(22, 7);");
script.my_basic.mb_run(bas);
script.my_basic.mb_close(out bas);
script.my_basic.mb_dispose();
- Principles
- Coding
- Data types
- Standalone shell
- Integration
- Customization
- More scripting API
- FAQ