Is it possible to pass a int from C# to C++ by reference?
I have a simple method in C++ that just increment a number and print messages.
void ProcessOrder(int& num)
{
int start = num;
int stop = num + 10;
for (int i = start; i < stop; i++)
{
cout << "[Legacy] counting " << i << endl;
}
cout << endl;
// Note the above was original posted code and I made a stupid mistake and was never
// even changing `num` value passed by reference. The correct function to test
// should be as below (discard all of the above)
num = num + 5; // just modify the number to any value
}
Now I want to call this from C++/CLI and then that from C#.
void StoreWrapper::ProcessOrder(int^ num)
{
LegacyStore* legacyStore = new LegacyStore();
legacyStore->ProcessOrder(num); // error here
}
But this returns compiler error:
error C2664: 'void LegacyStore::ProcessOrder(int &)': cannot convert argument 1 from 'System::Int32 ^' to 'int &'
I made sure all three projects are x86 but the error still persists. To be price, the CLR module is Win32 and C# Console application is x86.
The issues are here:
If I declare void StoreWrapper::ProcessOrder(int& num)
then this method compiles but now I believe its pure C++? I can't call this from C# side, get the following compiler err:
error CS1503: Argument 1: cannot convert from 'int' to 'int*'
If I declare it `void StoreWrapper::ProcessOrder(int^ num)' now the method doesn't even compile.
I have tried using System::Int32
variable type but same result.
Is there a way I pass int to C++ from .NET world by reference? Is it possible if C++ side is 32 bit and .NET side is 64 bit?
Update
The C# code is here, basically I want the number to get updated in the code below.
int number = 0;
Console.WriteLine("Original number = {0}", number);
store.ProcessOrder(ref number);
Console.WriteLine("After ProcessOrder number = {0}", number);
The answer by dxiv unfortunately doesn't update the number above.
Attempting to use num
directly like ProcessOrder(num);
fails with the error quoted in the original post "cannot convert argument 1 from System::Int32 ^
to int &
" because of the different levels of indirection between the passed (pointer) variable and the expected (reference) argument.
Attempting to fix that with ProcessOrder(*num);
corrects the indirection and gets the types to match, but fails to compile with the error "an object from the gc heap (an unboxed value type) cannot be converted to a native reference". This points to the real issue, which is that an unmanaged/unboxed reference cannot point into the gc managed heap, which is subject to compacting and reshuffles.
The easiest solution is to use a tracking reference int%
instead, as advised in the answer to the question linked as a duplicate.
void StoreWrapper::ProcessOrder(int% num)
{
LegacyStore* legacyStore = new LegacyStore();
legacyStore->ProcessOrder(*&num); // shorthand for:
//
// int &n = *#
// legacyStore->ProcessOrder(n);
// num = n;
}
// to be called from C# as:
//
// int number = 0;
// store.ProcessOrder(ref number);
num
by address, though that requires explicit pinning.
void StoreWrapper::ProcessOrder([System::Runtime::InteropServices::Out] int %num)
{
LegacyStore* legacyStore = new LegacyStore();
pin_ptr<int> p = #
legacyStore->ProcessOrder(*p);
}
// to be called from C# as:
//
// int number = 0;
// store.ProcessOrder(out number);