// // How do we support "null" values, should the caller take care of that? // // The caller is responsible for calling value_free_value on the returned Value public static Value FromObject (object v, bool box_value_types) { Value value = new Value (); unsafe { // get rid of this case right away. if (box_value_types && v.GetType().IsValueType) { //Console.WriteLine ("Boxing a value of type {0}:", v.GetType()); GCHandle handle = GCHandle.Alloc (v); value.k = Deployment.Current.Types.TypeToKind (v.GetType ()); value.IsGCHandle = true; value.u.p = GCHandle.ToIntPtr (handle); return value; } if (v is IEasingFunction && !(v is EasingFunctionBase)) v = new EasingFunctionWrapper (v as IEasingFunction); if (v is INativeEventObjectWrapper) { INativeEventObjectWrapper dov = (INativeEventObjectWrapper) v; if (dov.NativeHandle == IntPtr.Zero) throw new Exception (String.Format ( "Object {0} has not set its native property", dov.GetType())); NativeMethods.event_object_ref (dov.NativeHandle); value.k = dov.GetKind (); value.u.p = dov.NativeHandle; } else if (v is DependencyProperty) { value.k = Kind.DEPENDENCYPROPERTY; value.u.p = ((DependencyProperty)v).Native; } else if (v is int || (v.GetType ().IsEnum && Enum.GetUnderlyingType (v.GetType()) == typeof(int))) { value.k = Deployment.Current.Types.TypeToKind (v.GetType ()); value.u.i32 = (int) v; } else if (v is bool) { value.k = Kind.BOOL; value.u.i32 = ((bool) v) ? 1 : 0; } else if (v is double) { value.k = Kind.DOUBLE; value.u.d = (double) v; } else if (v is float) { value.k = Kind.FLOAT; value.u.f = (float) v; } else if (v is long) { value.k = Kind.INT64; value.u.i64 = (long) v; } else if (v is TimeSpan) { TimeSpan ts = (TimeSpan) v; value.k = Kind.TIMESPAN; value.u.i64 = ts.Ticks; } else if (v is ulong) { value.k = Kind.UINT64; value.u.ui64 = (ulong) v; } else if (v is uint) { value.k = Kind.UINT32; value.u.ui32 = (uint) v; } else if (v is char) { value.k = Kind.CHAR; value.u.ui32 = (uint) (char) v; } else if (v is string) { value.k = Kind.STRING; value.u.p = StringToIntPtr ((string) v); } else if (v is Rect) { Rect rect = (Rect) v; value.k = Kind.RECT; value.u.p = Marshal.AllocHGlobal (sizeof (Rect)); Marshal.StructureToPtr (rect, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is Size) { Size size = (Size) v; value.k = Kind.SIZE; value.u.p = Marshal.AllocHGlobal (sizeof (Size)); Marshal.StructureToPtr (size, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is CornerRadius) { CornerRadius corner = (CornerRadius) v; value.k = Kind.CORNERRADIUS; value.u.p = Marshal.AllocHGlobal (sizeof (CornerRadius)); Marshal.StructureToPtr (corner, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is AudioFormat) { AudioFormat f = (AudioFormat) v; value.k = Kind.AUDIOFORMAT; value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedAudioFormat)); UnmanagedAudioFormat *format = (UnmanagedAudioFormat*) value.u.p; format->bitsPerSample = f.BitsPerSample; format->channels = f.Channels; format->samplesPerSecond = f.SamplesPerSecond; format->waveFormat = f.WaveFormat; } else if (v is VideoFormat) { VideoFormat f = (VideoFormat) v; value.k = Kind.VIDEOFORMAT; value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedVideoFormat)); UnmanagedVideoFormat *format = (UnmanagedVideoFormat*) value.u.p; format->framesPerSecond = f.FramesPerSecond; format->height = f.PixelHeight; format->width = f.PixelWidth; format->stride = f.Stride; format->pixelFormat = f.PixelFormat; } else if (v is Point) { Point pnt = (Point) v; value.k = Kind.POINT; value.u.p = Marshal.AllocHGlobal (sizeof (Point)); Marshal.StructureToPtr (pnt, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is Thickness) { Thickness thickness = (Thickness)v; value.k = Kind.THICKNESS; value.u.p = Marshal.AllocHGlobal (sizeof (Thickness)); Marshal.StructureToPtr (thickness, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is Color) { Color c = (Color) v; value.k = Kind.COLOR; value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedColor)); UnmanagedColor* color = (UnmanagedColor*) value.u.p; color->r = c.R / 255.0f; color->g = c.G / 255.0f; color->b = c.B / 255.0f; color->a = c.A / 255.0f; } else if (v is Matrix) { // hack around the fact that managed Matrix is a struct while unmanaged Matrix is a DO // i.e. the unmanaged and managed structure layouts ARE NOT equal return FromObject (new UnmanagedMatrix ((Matrix) v), box_value_types); } else if (v is StylusPoint) { return FromObject (new UnmanagedStylusPoint ((StylusPoint) v), box_value_types); } else if (v is Matrix3D) { // hack around the fact that managed Matrix3D is a struct while unmanaged Matrix3D is a DO // i.e. the unmanaged and managed structure layouts ARE NOT equal return FromObject (new UnmanagedMatrix3D ((Matrix3D) v), box_value_types); } else if (v is Duration) { Duration d = (Duration) v; value.k = Kind.DURATION; value.u.p = Marshal.AllocHGlobal (sizeof (Duration)); Marshal.StructureToPtr (d, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is KeyTime) { KeyTime k = (KeyTime) v; value.k = Kind.KEYTIME; value.u.p = Marshal.AllocHGlobal (sizeof (KeyTime)); Marshal.StructureToPtr (k, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is RepeatBehavior) { RepeatBehavior d = (RepeatBehavior) v; value.k = Kind.REPEATBEHAVIOR; value.u.p = Marshal.AllocHGlobal (sizeof (RepeatBehavior)); Marshal.StructureToPtr (d, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is FontFamily) { FontFamily family = (FontFamily) v; value.k = Kind.FONTFAMILY; value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontFamily)); Marshal.StructureToPtr (family, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is FontSource) { FontSource source = (FontSource) v; value.k = Kind.FONTSOURCE; if (source.wrapper != null || source.typeface != null) { value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontSource)); UnmanagedFontSource *ufs = (UnmanagedFontSource *) value.u.p; ufs->type = source.type; switch (source.type) { case FontSourceType.ManagedStream: ManagedStreamCallbacks callbacks = source.wrapper.GetCallbacks (); ufs->source.stream = Marshal.AllocHGlobal (sizeof (UnmanagedStreamCallbacks)); Marshal.StructureToPtr (callbacks, ufs->source.stream, false); break; case FontSourceType.GlyphTypeface: ufs->source.typeface = source.typeface.Native; break; } } else { value.IsNull = true; } } else if (v is PropertyPath) { PropertyPath propertypath = (PropertyPath) v; value.k = Kind.PROPERTYPATH; value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedPropertyPath)); UnmanagedPropertyPath *upp = (UnmanagedPropertyPath *) value.u.p; upp->property = propertypath.NativeDP; if (upp->property == IntPtr.Zero) upp->pathString = StringToIntPtr (propertypath.Path); else upp->pathString = IntPtr.Zero; upp->expandedPathString = IntPtr.Zero; } else if (v is Uri) { Uri uri = (Uri) v; value.k = Kind.URI; value.u.p = UnmanagedUri.FromUri (uri); } else if (v is XmlLanguage) { XmlLanguage lang = (XmlLanguage) v; value.k = Kind.STRING; value.u.p = StringToIntPtr (lang.IetfLanguageTag); } else if (v is Cursor) { Cursor c = (Cursor) v; value.k = Kind.CURSORTYPE; value.u.i32 = (int)c.cursor; } else if (v is GridLength) { GridLength gl = (GridLength) v; value.k = Kind.GRIDLENGTH; value.u.p = Marshal.AllocHGlobal (sizeof (GridLength)); Marshal.StructureToPtr (gl, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is FontStretch) { FontStretch stretch = (FontStretch) v; value.k = Kind.FONTSTRETCH; value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontStretch)); Marshal.StructureToPtr (stretch, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is FontStyle) { FontStyle style = (FontStyle) v; value.k = Kind.FONTSTYLE; value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontStyle)); Marshal.StructureToPtr (style, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is FontWeight) { FontWeight weight = (FontWeight) v; value.k = Kind.FONTWEIGHT; value.u.p = Marshal.AllocHGlobal (sizeof (UnmanagedFontWeight)); Marshal.StructureToPtr (weight, value.u.p, false); // Unmanaged and managed structure layout is equal. } else if (v is TextDecorationCollection) { value.k = Kind.TEXTDECORATIONS; value.u.i32 = (int) (v as TextDecorationCollection).Kind; } else if (v is Type) { Type t = v as Type; ManagedTypeInfo mti = new ManagedTypeInfo (); mti.full_name = StringToIntPtr (t.FullName); mti.Kind = Deployment.Current.Types.TypeToKind (t); value.k = Kind.MANAGEDTYPEINFO; value.u.p = Marshal.AllocHGlobal (sizeof (ManagedTypeInfo)); Marshal.StructureToPtr (mti, value.u.p, false); } else { //Console.WriteLine ("Do not know how to encode {0} yet, boxing it", v.GetType ()); // TODO: We probably need to marshal types that can animate as the // corresponding type (Point, Double, Color, etc). // TODO: We need to store the GCHandle somewhere so that we can free it, // or register a callback on the surface for the unmanaged code to call. GCHandle handle = GCHandle.Alloc (v); value.IsGCHandle = true; value.k = Deployment.Current.Types.TypeToKind (v.GetType ()); value.u.p = GCHandle.ToIntPtr (handle); } } return value; }