[Mono-list] DllImport and extern declarations for values
Jonathan Pryor
jonpryor@vt.edu
Tue, 30 Sep 2003 07:47:13 -0400
Responses inline...
On Tue, 2003-09-30 at 05:07, Thomas Sondergaard wrote:
> I have written a ruby extension module in managed C++ that allows ruby to
> interop with .net. I want this to work with mono on linux and since the
> managed C++ is not portable I am rewriting as much as possible to C# using
> P/Invoke. Ideally I would only have to write a small stub of a dynamic link
> library that exports the init function called by ruby, which uses the Mono
> embedding API and then I can do the rest from C#.
>
> I have made a C# class called RubyAPI, where I have manually entered all the
> ruby functions I use from the ruby api. It looks something like this:
>
>
> namespace RubyDotNet.Common {
> public class RubyAPI {
>
> [DllImport(@"c:/ruby180/bin/msvcrt-ruby18.dll")]
> public static extern void ruby_init();
>
> [DllImport(@"c:/ruby180/bin/msvcrt-ruby18.dll")]
> public static extern void ruby_finalize();
>
> [DllImport(@"c:/ruby180/bin/msvcrt-ruby18.dll")]
> public static extern uint
> rb_eval_string([MarshalAs(UnmanagedType.LPStr)] string s);
>
> ...
> }
> }
I would suggest that you leave out the pathnames in the DllImport
statements, unless you want to guarantee that all users (on all
platforms!) will have it in the same location.... :-)
> The thing is, in C++ I also use a few macros, which I won't be able to use
> either, but I can probably manage that by duplicating it in C# (yuck,
> duplication).
I miss macros as well. Though a lisp-like macro system would be an
interesting addition to C#.... Which will never happen, obviously.
> I do however need to reference som global constants defined in
> ruby.h like this:
>
> typedef unsigned long VALUE;
>
> EXTERN VALUE rb_mKernel;
> EXTERN VALUE rb_mComparable;
> EXTERN VALUE rb_mEnumerable;
> EXTERN VALUE rb_mPrecision;
> EXTERN VALUE rb_mErrno;
> EXTERN VALUE rb_mFileTest;
> EXTERN VALUE rb_mGC;
> EXTERN VALUE rb_mMath;
> EXTERN VALUE rb_mProcess;
>
> How can I DllImport these? I tried:
>
> [DllImport(@"c:/ruby180/bin/msvcrt-ruby18.dll")]
> public static extern /* VALUE */ uint rb_cModule;
>
> but that doesn't work.
You can't DllImport a variable. Primarily because the PE file format
doesn't support exporting variables (IIRC).
> Is there a smarter way to do this, where I don't have to manually duplicate
> all this? Like a utility program that will generate a managed wrapper class
> with static methods given a .h file.
You can take a look at the gtk-sharp CVS module, which contains a Perl
script to parse C code and generate XML files (containing classes,
enumerations, constants, etc.), which are then used to generate the C#
class definitions.
Though that might be overkill. Yes, you should use a utility program.
It'll probably be easiest to just custom write your own in Ruby. It
should be easy enough to create a regex that will grab the variable
name, attach a suffix, use that for a function, and implement it.
> What is the performance overhead of using P/Invoke instead of IJW (It Just
> Works) in managed C++?
IJW is basically an implicit P/Invoke. It uses the same runtime
mechanism to call native functions.
At least, that was my impression reading the documentation last year.
> What is the state of Mono P/Invoke, DllImport, MarshalAs etc.
It mostly works. I ran across one unimplemented feature for marshaling
LPWStr types, but that's not particularly common under Unix anyway.
> What about
> System.Reflection and System.Reflection.Emit?
Mono arguably has a better implementation than .NET. :-)
MCS uses System.Reflection.Emit, and a couple enhancements needed to be
made so that all of C# could be easily implemented using S.R.E.
- Jon