0

I am trying to use a C# DLL which has multiple references to .NET classes and C# Classes in Embarcadero C++ Builder. Things like the Point class and String class as well as Delegates.

I am wondering if the >NET references or C# ones will mess me up somehow. I am just about to getting it hooked up, but I am wondering if some of the problems I am having could be caused by C++ not wanting to play nice.

Kromster
  • 7,181
  • 7
  • 63
  • 111
Roberto
  • 1
  • 3

3 Answers3

1

I gave a similar answer to your problem in this question.

You basically want a C++/CLI interface to your C# code.

If you want to pass a C# delegate to C++ code, you can translate it using Marshal::GetFunctionPointerForDelegate() (MSDN). That gives you a IntPtr that you can call ToPointer() on to pass in as a function pointer.

Community
  • 1
  • 1
Soo Wei Tan
  • 3,262
  • 2
  • 34
  • 36
  • Interesting, more lightweight approach. The initiative will have to be from C#, but you can transfer the control back to native code and have callbakcs. Could be very useful, thanks – sehe Apr 02 '11 at 09:55
0

You will need to use C++/CLI to use any .NET content in C++. You might also be able to set up your own AppDomain, but those are the only two choices, as C++ has no native ability to interact with .NET, at all.

Puppy
  • 144,682
  • 38
  • 256
  • 465
0

Or you can use the mono CLR embedder

Managed code can invoke unmanaged code in two ways, [using P/Invoke or] using the low-level Mono embedding API.

This works a lot like the oldfashioned embedding of a Perl, Python or Ruby 'interpreter' (actually, virtual machines) in your C/C++ executable. I don't think there is actually such a thing as a Swig(++) wrapper generator for this (yet), but here is a snippet of what a call into CIL code looks like:

 class MyClass {
    static void Foo (int value) {
      ...
    }

    int Bar (string name) {
      ...
    }
  }

assuming you got the corresponding MonoMethod* in foo_method and bar_method and this_arg is a MonoObject* of type MyClass, you simply execute:

  /* we execute methods that take one argument */
  void *args [1];
  int val = 10;
  /* Note we put the address of the value type in the args array */
  args [0] = &val;

  /* execute Foo (10);
   * it's a static method, so use NULL as the second argument.
   */
  mono_runtime_invoke (foo_method, NULL, args, NULL);

  /* a string is a reference, so we put it directly in the args array */
  args [0] = mono_string_new (domain, "Hello");
  /* execute my_class_instance.Bar ("Hello");
   * See the Creating Objects section to learn how to get this_arg.
   */
  MonoObject *result = mono_runtime_invoke (bar_method, this_arg, args, NULL);
  /* we always get a MonoObject* from mono_runtime_invoke (), so to get
   * the integer value we need to unbox (which returns a pointer to
   * the value stored in the object) and dereference.
   */
  int int_result = *(int*)mono_object_unbox (result);

For extra entertainment value: if you AOT-compile all of your CIL code, you'll be able to statically link your assembly into your native binary (effectively doing what Managed C++ (c++-cli) calls mixed mode assemblies). Look at

 mono --aot=static myassembly.dll

and

 mkbundle
sehe
  • 374,641
  • 47
  • 450
  • 633
  • In this case, it's unmanaged code calling managed code, which rules out p/invoke. – Joe Apr 01 '11 at 22:05
  • That's ok, did you get the rest of the message? Both ways are supported :) – sehe Apr 01 '11 at 22:07
  • I'm curious, how do you use P/Invoke for calling C# code from native C++ code? – Soo Wei Tan Apr 01 '11 at 22:51
  • I'm curious too. How come I have a 20+ line code snippet, 2 web references, devoted to calling into C# from C++ code, yet all commentors stumble across the _SINGLE_ word P/Invoke? I think I'll un-bold it, for all us-programming-short-attention-span-readers see nothing else.... – sehe Apr 01 '11 at 22:54
  • I guess I was more interested in a P/Invoke solution for calling C# code from C++. The Mono method is interesting too. – Soo Wei Tan Apr 02 '11 at 00:18
  • @Soo Wei Tan: You might consider asking that as a question. I'm pretty sure a P/Invoke like mechanism can be achieved with a little more plumbing on the .NET side. Perhaps someone has done it before – sehe Apr 02 '11 at 09:53
  • It seems to me, though perhaps I am just misunderstanding these methods, that these would require to to have written or at least have access to the C# code for the DLL. I do not have this and am looking for a way to simply take any .NET DLL and access it using C++. If this is case for your suggestions then thank you, could you please point out where I may have been mistaken? Also, I was under the impression that C++/CLI was only usable in VS. Seeing as I am using Embarcadero I didn't think this would be possible. – Roberto Apr 04 '11 at 13:06
  • @Roberto: I certainly didn't mention C++/CLI in my post. This is embedding the mono JIT engine; it works on Windows and Linux (and Mac?). And yes, as such you can access any odd .NET assembly, not just C# and also without the source. HTH – sehe Apr 04 '11 at 15:21
  • Sorry Sehe, I don't have the option to implement an API to solve this. I need a solution that is entirely within Builder, easily done through command line, or something similar. – Roberto Apr 05 '11 at 11:15
  • Yeah I get that a lot. 'I want it all, it needs to lay golden eggs (without making noise) and It must not look like anything new'. I don't think I'll be able to help with that -- Perhaps you should review your architecture decisions before you go much further – sehe Apr 05 '11 at 11:20
  • While that's an interesting approach there, my architecture designs are not up to me. It is simply sloppy code to drag in a whole API to do a procedure that Embarcadero practically automates for you. – Roberto Apr 05 '11 at 18:14
  • I have nearly solved the problem on my own: Use Embarcadero's "Import .NET Assembly" ability (or it's "Import TLB" ability) and edit the output. If you used certain calls and classes from C# (which I did and is why I was asking this question) it will create a file called "mscorlib_TLB.h". This file WILL have errors in it. It uses a variable called "or". If you are familiar with new C++'s ability to use the words "and" and "or" instead of && and || then you can see the problem. (continued)--> – Roberto Apr 05 '11 at 18:21
  • Disabling this setting (or changing all instances of that variable to something else) will fix the problem. After that I just had to make sure my DLL was all set to go using this site: http://interop.managed-vcl.com/netinterop_csharp.php And I was pretty much done. My goose lays some mighty gold eggs. – Roberto Apr 05 '11 at 18:22
  • @Roberto: this is nice info. Effectively you are able to use the bulk of .Net via interop. Why don't you post it as an answer, so it can be upvoted? – sehe Apr 05 '11 at 21:02
  • 1
    It's still got a bug or two. I seem to only be able to create a fully functioning TLB using that website's tool as opposed to Embarcadero's import function. Same output more or less but a slightly more involved procedure. Once I figure out why/get it sorted out I will post a full answer. – Roberto Apr 05 '11 at 21:23