I have attached some code that demonstrates the problem. My intent is to use a custom marshaler to make a copy of the return value object in a freshly allocated C# object reference. (The validity of this technique is what I am evaluating, so it's possible I am going down the wrong road with this.)
The output from running the C# application is the following:
Marshal::Marshal() new_Marshal() -- mb: 0x80f0580 new_Marshal() -- mb->mRef.x: 51 DataUser.DataUser() -- mRawObject: 0x80f0580 DataUser.getReferenceCopy() -- mRawObject: 0x80f0580 Marshal_getReferenceCopy() -- self_: 0x80c3d20 Marshal_getReferenceCopy() -- self_->mRef.x: 135533516 MarshalNativeToManaged() -- nativeObj: 0x80f0580 MarshalNativeToManaged() -- obj's value: 135533516 Reference copy value: 135533516
mRawObject (C#) and self_ (C/C++) should always have the same value, but notice that when DataUser.getReferenceCopy() is called, the value of the pointer changes from 0x80f0580 to 0x80c3d20, but my custom marshaler's MarshalNativeToManaged() gets 0x80f0580 as the value of its argument, nativeObj.
By adding a second garbage argument to Marshal_getReferenceCopy(), I was able to determine that the first argument is what gets passed to my custom marshaler and the second is the value of mRawObject. Am I misunderstanding something about how to marshal return values? Is my approach to C++ object return value copying fubared? Is there a specific place in the Mono source I could examine to try get a more in-depth understanding of Mono is trying to do here?
-Patrick
-- Patrick L. Hartling | Research Assistant, VRAC [EMAIL PROTECTED] | 2624 Howe Hall: 1.515.294.4916 http://www.137.org/patrick/ | http://www.vrac.iastate.edu/
// To compile: // c++ -o libreturn_copy.so return_copy.cpp
#include <iostream>
#include <iomanip>
class ReferenceData
{
public:
ReferenceData() : x(0)
{
}
unsigned int x;
};
class Marshal
{
public:
Marshal()
{
std::cout << "Marshal::Marshal()" << std::endl;
mRef.x = 51;
}
ReferenceData getReferenceCopy()
{
return mRef;
}
private:
ReferenceData mRef;
};
extern "C"
{
Marshal* new_Marshal()
{
Marshal* mb = new Marshal;
std::cout << "new_Marshal() -- mb: " << std::hex << mb << std::dec
<< std::endl;
std::cout << "new_Marshal() -- mb->mRef.x: " << mb->getReferenceCopy().x
<< std::endl;
return (Marshal*) mb;
}
ReferenceData Marshal_getReferenceCopy(Marshal* self_)
{
std::cout << "Marshal_getReferenceCopy() -- self_: " << std::hex
<< self_ << std::dec << std::endl;
std::cout << "Marshal_getReferenceCopy() -- self_->mRef.x: "
<< self_->getReferenceCopy().x << std::endl;
return self_->getReferenceCopy();
}
}
// To compile:
// mcs return_copy.cs
using System;
using System.Runtime.InteropServices;
namespace test
{
[StructLayout(LayoutKind.Sequential)]
class ReferenceData
{
public override string ToString()
{
return x.ToString();
}
public uint x;
};
class ReferenceDataMarshaler : ICustomMarshaler
{
public void CleanUpManagedData(Object obj)
{
}
public void CleanUpNativeData(IntPtr nativeData)
{
}
public int GetNativeDataSize()
{
return -1;
}
public IntPtr MarshalManagedToNative(Object obj)
{
return new IntPtr((int) ((ReferenceData) obj).x);
}
public Object MarshalNativeToManaged(IntPtr nativeObj)
{
ReferenceData obj = new ReferenceData();
obj.x = (uint) Marshal.ReadInt32(nativeObj);
Console.WriteLine("MarshalNativeToManaged() -- nativeObj: 0x{0:x}",
nativeObj.ToInt32());
Console.WriteLine("MarshalNativeToManaged() -- obj's value: " + obj);
return obj;
}
public static ICustomMarshaler GetInstance(string cookie)
{
return mInstance;
}
private static ReferenceDataMarshaler mInstance = new ReferenceDataMarshaler();
};
class DataUser
{
protected internal IntPtr mRawObject;
[DllImport("return_copy", CharSet=CharSet.Ansi)]
private static extern IntPtr new_Marshal();
public DataUser()
{
mRawObject = new_Marshal();
Console.WriteLine("DataUser.DataUser() -- mRawObject: 0x{0:x}",
mRawObject.ToInt32());
}
[DllImport("return_copy")]
[return : MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ReferenceDataMarshaler))]
private static extern ReferenceData Marshal_getReferenceCopy(IntPtr instPtr);
public ReferenceData getReferenceCopy()
{
Console.WriteLine("DataUser.getReferenceCopy() -- mRawObject: 0x{0:x}",
mRawObject.ToInt32());
return Marshal_getReferenceCopy(mRawObject);
}
};
class Tester
{
public static void Main()
{
DataUser u = new DataUser();
Console.WriteLine("Reference copy value: " + u.getReferenceCopy());
}
}
}
