2004-02-18 Martin Baulig <martin@ximian.com>
[mono.git] / mono / tests / marshal10.cs
1 // A demonstration of a custom marshaler that marshals
2 // unmanaged to managed data.
3
4 using System;
5 using System.Runtime.InteropServices;
6
7 public class MyMarshal: ICustomMarshaler
8 {
9
10         // GetInstance() is not part of ICustomMarshaler, but
11         // custom marshalers are required to implement this
12         // method.
13         public static ICustomMarshaler GetInstance (string s)
14         {
15                 Console.WriteLine ("GetInstance called");
16                 return new MyMarshal ();
17         }
18         
19         public void CleanUpManagedData (object managedObj)
20         {
21                 Console.WriteLine ("CleanUpManagedData called");
22         }
23
24         public void CleanUpNativeData (IntPtr pNativeData)
25         {
26                 Console.WriteLine("CleanUpNativeData called");
27                 if (pNativeData != IntPtr.Zero)
28                         Marshal.FreeHGlobal (pNativeData);
29         }
30
31
32         // I really do not understand the purpose of this method
33         // or went it would be called. In fact, Rotor never seems
34         // to call it.
35         public int GetNativeDataSize ()
36         {
37                 Console.WriteLine("GetNativeDataSize() called");
38                 return 4;
39         }
40
41         public IntPtr MarshalManagedToNative (object managedObj)
42         {
43                 Console.WriteLine("MarshalManagedToNative()");
44                 return IntPtr.Zero;
45         }
46
47
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)
53         {
54                 Console.WriteLine("MarshalNativeToManaged()");
55                 return "*" + Marshal.PtrToStringAnsi( pNativeData ) + "*";
56         }
57 }
58
59 // From Gtk#
60 public class time_t_CustomMarshaler : ICustomMarshaler {
61
62         static time_t_CustomMarshaler marshaler;
63         int utc_offset;
64         DateTime local_epoch;
65
66         private time_t_CustomMarshaler () 
67         {
68                 utc_offset = (int) DateTime.Now.Subtract (DateTime.UtcNow).TotalSeconds;
69                 local_epoch = new DateTime (1970, 1, 1, 0, 0, 0);
70         }
71
72         public static ICustomMarshaler GetInstance (string cookie)
73         {
74                 if (marshaler == null)
75                         marshaler = new time_t_CustomMarshaler ();
76
77                 return marshaler;
78         }
79
80         public IntPtr MarshalManagedToNative (object obj)
81         {
82                 //
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
87                 // as the parameter
88                 //
89
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);
99                 else
100                         throw new Exception ("Unexpected native size for time_t.");
101
102                 return ptr;
103         }
104
105         public void CleanUpNativeData (IntPtr data)
106         {
107                 Marshal.FreeCoTaskMem (data);
108         }
109
110         public object MarshalNativeToManaged (IntPtr data)
111         {
112                 //
113                 // This function receives the return value of the unmanaged function
114                 // as a pointer.
115                 //
116
117                 int secs;
118                 secs = (int)data;
119
120                 TimeSpan span = new TimeSpan (0, 0, secs - utc_offset);
121                 return local_epoch.Add (span);
122         }
123
124         public void CleanUpManagedData (object obj)
125         {
126         }
127
128     [DllImport("libtest")]
129         private static extern int time_t_sizeof ();
130
131         public int GetNativeDataSize ()
132         {
133                 return time_t_sizeof ();
134         }
135 }
136
137 public class Testing
138 {
139         [DllImport("libtest")]
140         [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
141         private static extern string functionReturningString();
142
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))]
147                  DateTime t);
148
149         public static int Main()
150         {
151                 string res = functionReturningString();
152                 Console.WriteLine ("native string function returns {0}", res);
153
154                 if (res != "*ABC*")
155                         return 1;
156
157                 DateTime d = DateTime.Now;
158                 DateTime d2 = mono_test_marshal_time_t (d);
159
160                 if (((d2 - d).TotalSeconds < 3599) || ((d2 - d).TotalSeconds > 3601))
161                         return 2;
162
163                 return 0;
164         }
165
166
167
168 }