1 // A demonstration of a custom marshaler that marshals
2 // unmanaged to managed data.
5 using System.Runtime.InteropServices;
7 public class MyMarshal: ICustomMarshaler
10 // GetInstance() is not part of ICustomMarshaler, but
11 // custom marshalers are required to implement this
13 public static ICustomMarshaler GetInstance (string s)
15 Console.WriteLine ("GetInstance called");
16 return new MyMarshal ();
19 public void CleanUpManagedData (object managedObj)
21 Console.WriteLine ("CleanUpManagedData called");
24 public void CleanUpNativeData (IntPtr pNativeData)
26 Console.WriteLine("CleanUpNativeData called");
27 if (pNativeData != IntPtr.Zero)
28 Marshal.FreeHGlobal (pNativeData);
32 // I really do not understand the purpose of this method
33 // or went it would be called. In fact, Rotor never seems
35 public int GetNativeDataSize ()
37 Console.WriteLine("GetNativeDataSize() called");
41 public IntPtr MarshalManagedToNative (object managedObj)
43 Console.WriteLine("MarshalManagedToNative()");
48 // Convert a pointer to unmanaged data into a System.Object.
49 // This method simply converts the unmanaged Ansi C-string
50 // into a System.String and surrounds it with asterisks
51 // to differentiate it from the default marshaler.
52 public object MarshalNativeToManaged (IntPtr pNativeData)
54 Console.WriteLine("MarshalNativeToManaged()");
55 return "*" + Marshal.PtrToStringAnsi( pNativeData ) + "*";
60 public class time_t_CustomMarshaler : ICustomMarshaler {
62 static time_t_CustomMarshaler marshaler;
66 private time_t_CustomMarshaler ()
68 utc_offset = (int) DateTime.Now.Subtract (DateTime.UtcNow).TotalSeconds;
69 local_epoch = new DateTime (1970, 1, 1, 0, 0, 0);
72 public static ICustomMarshaler GetInstance (string cookie)
74 if (marshaler == null)
75 marshaler = new time_t_CustomMarshaler ();
80 public IntPtr MarshalManagedToNative (object obj)
83 // This method should return a pointer to a memory buffer holding
84 // the unmanaged representation of 'obj'
85 // The first 4 bytes of the buffer is unused
86 // The unmanaged function will receive the address of the buffer
90 DateTime dt = (DateTime) obj;
91 int size = Marshal.SizeOf (typeof (int)) + GetNativeDataSize ();
92 IntPtr ptr = Marshal.AllocCoTaskMem (size);
93 IntPtr time_t_ptr = new IntPtr (ptr.ToInt32 () + Marshal.SizeOf (typeof(int)));
94 int secs = ((int)dt.Subtract (local_epoch).TotalSeconds) + utc_offset;
95 if (GetNativeDataSize () == 4)
96 Marshal.WriteInt32 (time_t_ptr, secs);
97 else if (GetNativeDataSize () == 8)
98 Marshal.WriteInt64 (time_t_ptr, secs);
100 throw new Exception ("Unexpected native size for time_t.");
105 public void CleanUpNativeData (IntPtr data)
107 Marshal.FreeCoTaskMem (data);
110 public object MarshalNativeToManaged (IntPtr data)
113 // This function receives the return value of the unmanaged function
120 TimeSpan span = new TimeSpan (0, 0, secs - utc_offset);
121 return local_epoch.Add (span);
124 public void CleanUpManagedData (object obj)
128 [DllImport("libtest")]
129 private static extern int time_t_sizeof ();
131 public int GetNativeDataSize ()
133 return time_t_sizeof ();
139 [DllImport("libtest")]
140 [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
141 private static extern string functionReturningString();
143 [DllImport("libtest", EntryPoint="mono_test_marshal_time_t")]
144 [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(time_t_CustomMarshaler))]
145 private static extern DateTime mono_test_marshal_time_t (
146 [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(time_t_CustomMarshaler))]
149 public static int Main()
151 string res = functionReturningString();
152 Console.WriteLine ("native string function returns {0}", res);
157 DateTime d = DateTime.Now;
158 DateTime d2 = mono_test_marshal_time_t (d);
160 if (((d2 - d).TotalSeconds < 3599) || ((d2 - d).TotalSeconds > 3601))