10

It seems like there must be a duplicate question, but I haven't been able to find it.

I'm writing a bridge to let an old C program access some C# objects. The bridge is written in C++/CLI.

In one case there is a C# function that's defined as:

public static string GetNameAndValue(out int value);

My C++/CLI wrapper function:

char* GetNameAndValue(int* value);

Which is easy enough to call from C. But how do I call the C# method from C++/CLI?

I first tried the obvious:

String ^ str;
str = TheObject::GetNameAndValue(value);

That gives me error C2664: Cannot convert parameter 2 from 'int *' to 'int %'.

Okay, then, how about GetNameAndValue(%value)? That gives me error C3071: operator '%' can only be applied to an instance of a ref class or a value-type.

Fair enough. So if I create an int I can pass it with %??

int foo;
str = TheObject::GetNameAndValue(%ix);

No dice. C3071 again. Which I find odd because int definitely is a value-type. Or is it?

There must be some magic combination of %, ^, &, or some other obscenity that will do what I want, but after swearing at this thing for 30 minutes I'm stumped. And searching Google for different combinations of C++/CLI and C# mostly gives information about how to call C++ from C#.

SO, my question: How do you pass an int from C++/CLI to a C# method that expects an out int (or ref int, if I have to)?

3
  • 1
    You've got things badly backwards. C++/CLI is pretty useless to allow a C program to call a C# method. It is a language extension that was made to go the other way, from managed code to native code. Running managed code from a native program requires much bigger weapons, it has to load and initialize the CLR first. That's going to take more than 30 minutes to sort out. Commented May 12, 2014 at 22:30
  • 1
    @HansPassant: That's not been my experience in the short time I've been working with this. My C program calls a DLL that was compiled with C++/CLI, which in turn calls C# code in another assembly. Works quite well. As I understand it, the C++/CLI DLL loads the runtime. Whatever the case, I've been able to get information from the C# code back to the C code. Commented May 12, 2014 at 23:19
  • C++/CLI supports __declspec(dllexport), that's the only scenario I can think of where you could have good luck with it. Same idea as Giesecke's [DllExport] hack. As posted, your question makes very little sense to me and the problems you are having are entirely normal. Good luck with it. Commented May 12, 2014 at 23:36

2 Answers 2

6

C#:

class MyClass 
{ 
    public static string GetNameAndValue(out int value);
}

C++/CLI:

int value;
String^ x = MyClass::GetNameAndValue(value);

C++/CLI wrapper:

CString GetNameAndValue(int* value)
{
    String^ x = MyClass::GetNameAndValue(*value);
    return CString(x);
}

C++/CLI wrapper 2:

CString GetNameAndValue(int& value)
{
    String^ x = MyClass::GetNameAndValue(value);
    return CString(x);
}

It's the same for C# "ref".

Sign up to request clarification or add additional context in comments.

4 Comments

That is totally non obvious! So when I do MyClass::GetNameAndValue(*value), the compiler is automatically marshaling it as something like [out] System::Int32? It'll take me a bit to test this, but if it works I'll accept the answer.
It's just like calling C++: "void x(int&);" by passing variable "int v;". Mechanism is the same. There is no cast. For compiler the desired prototype is the same as defined one.
What's more the only difference between ref and out is that out force you to assign the variable inside method. Otherwise you can think of ref as C++ &. By the way I use C++, C++/CLI, C# for a while and there is really no need to use % symbol, you can define it's equivalent in C# or C++. So in C++/CLI the only additional reference type symbol left to care about is ^.
There is no way to define anything like a tracking reference in C++. % in C++/CLI is unique in that it follows objects around when they move during a heap compaction. Objects moving around during their lifetime is a unique feature of .NET. It doesn't exist in C++, hence there is no facility for a matching reference.
1

I know this is answered already but only to clarify what the compiler was suggesting with "C2664: Cannot convert parameter 2 from 'int *' to 'int %'".
I think it wanted this(C++/CLI):

int a=5
int% foo=a;
str = TheObject::GetNameAndValue(foo);

2 Comments

Not really. It's a reference parameter, and can bind to an lvalue. You don't need to create another reference in the caller... and the parameter won't bind to the caller's reference anyway.
The whole point & purpose of my post was to be explicit and clear, without fancy terms. You are of course correct, but very academic. I am of the opinion that simple even over-trivial examples are better. This is actually the problem with MSDN : it is written in a very academic way, so it is counter-intuitive and difficult to grasp in a short time. That is why we have sites like this one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.