2004-06-03 Miguel de Icaza <miguel@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 (is this really 4 bytes on a 64bit machine?)
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                 int secs = ((int)dt.Subtract (local_epoch).TotalSeconds) + utc_offset;
94                 if (GetNativeDataSize () == 4)
95                         Marshal.WriteInt32 (ptr, secs);
96                 else if (GetNativeDataSize () == 8)
97                         Marshal.WriteInt64 (ptr, secs);
98                 else
99                         throw new Exception ("Unexpected native size for time_t.");
100
101                 return ptr;
102         }
103
104         public void CleanUpNativeData (IntPtr data)
105         {
106                 Marshal.FreeHGlobal (data);
107         }
108
109         public object MarshalNativeToManaged (IntPtr data)
110         {
111                 //
112                 // This function receives the return value of the unmanaged function
113                 // as a pointer.
114                 //
115
116                 int secs;
117                 secs = (int)data;
118
119                 TimeSpan span = new TimeSpan (0, 0, secs - utc_offset);
120                 return local_epoch.Add (span);
121         }
122
123         public void CleanUpManagedData (object obj)
124         {
125         }
126
127     [DllImport("libtest")]
128         private static extern int time_t_sizeof ();
129
130         public int GetNativeDataSize ()
131         {
132                 return time_t_sizeof ();
133         }
134 }
135
136 public class Testing
137 {
138         [DllImport("libtest")]
139         [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))]
140         private static extern string functionReturningString();
141
142     [DllImport("libtest", EntryPoint="mono_test_marshal_time_t")]
143         [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(time_t_CustomMarshaler))]
144         private static extern DateTime mono_test_marshal_time_t (
145                  [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(time_t_CustomMarshaler))]
146                  DateTime t);
147
148         public static int Main()
149         {
150                 string res = functionReturningString();
151                 Console.WriteLine ("native string function returns {0}", res);
152
153                 if (res != "*ABC*")
154                         return 1;
155
156                 DateTime d = DateTime.Now;
157                 DateTime d2 = mono_test_marshal_time_t (d);
158
159                 if (((d2 - d).TotalSeconds < 3599) || ((d2 - d).TotalSeconds > 3601))
160                         return 2;
161
162                 return 0;
163         }
164
165
166
167 }