Back to index

lightning-sunbird  0.9+nobinonly
xptinvoke.cs
Go to the documentation of this file.
00001 using System;
00002 using System.Runtime.InteropServices;
00003 using Mozilla.XPCOM;
00004 using System.Globalization;
00005 
00006 using MethodDescriptor = Mozilla.XPCOM.TypeInfo.MethodDescriptor;
00007 using ParamDescriptor = Mozilla.XPCOM.TypeInfo.ParamDescriptor;
00008 using ParamFlags = Mozilla.XPCOM.TypeInfo.ParamFlags;
00009 using TypeDescriptor = Mozilla.XPCOM.TypeInfo.TypeDescriptor;
00010 using TypeFlags = Mozilla.XPCOM.TypeInfo.TypeFlags;
00011 using TypeTag = Mozilla.XPCOM.TypeInfo.TypeTag;
00012 
00013 namespace Mozilla.XPCOM {
00014 
00015 [StructLayout(LayoutKind.Explicit)]
00016 struct XPTCMiniVariant
00017 {
00018     [FieldOffset(0)]
00019     public sbyte   i8;
00020     [FieldOffset(0)]
00021     public Int16  i16;
00022     [FieldOffset(0)]
00023     public Int32  i32;
00024     [FieldOffset(0)]
00025     public Int64  i64;
00026     [FieldOffset(0)]
00027     public byte    u8;
00028     [FieldOffset(0)]
00029     public UInt16 u16;
00030     [FieldOffset(0)]
00031     public UInt32 u32;
00032     [FieldOffset(0)]
00033     public UInt64 u64;
00034     [FieldOffset(0)]
00035     public float    f;
00036     [FieldOffset(0)]
00037     public double   d;
00038     [FieldOffset(0)]
00039     public Int32    b; /* PRBool */
00040     [FieldOffset(0)]
00041     public byte     c;
00042     [FieldOffset(0)]
00043     public char    wc;
00044     [FieldOffset(0)]
00045     public IntPtr   p;
00046     [FieldOffset(0),MarshalAs(UnmanagedType.LPStr)]
00047     public string str;
00048 }
00049 
00050 [StructLayout(LayoutKind.Explicit)]
00051 struct XPTCVariant
00052 {
00053     [FieldOffset(0)]
00054     public XPTCMiniVariant val;
00055     
00056     [FieldOffset(8)]
00057     public IntPtr          ptr;
00058     
00059     [FieldOffset(12)] /* XXX assumes 4-byte IntPtr! */
00060     public XPTType         type;
00061     
00062     [FieldOffset(13)]
00063     public sbyte          flags;
00064 }
00065 
00066 public class Invoker
00067 {
00068     static void MarshalOneArg(ParamDescriptor param, object arg,
00069                               IntPtr buffer)
00070     {
00071         string msg;
00072         if (param.flags != TypeInfo.ParamFlags.In) {
00073             msg = String.Format("{0} is {1} (only In " +
00074                               "supported)", param.Name(),
00075                               param.flags.ToString());
00076             throw new Exception(msg);
00077         }
00078 
00079         TypeInfo.TypeDescriptor type = param.type;
00080         
00081         if ((type.flags & TypeFlags.Reference) != 0) {
00082             if ((type.flags & TypeFlags.Pointer) == 0) {
00083                 throw new Exception("TD is Reference but " +
00084                                     "not Pointer?! (" +
00085                                     param.ToString() + ")");
00086             }
00087             
00088             if (arg == null) {
00089                 throw new Exception(param.Name() +
00090                                     ": null passed as arg for " + 
00091                                     "Reference param");
00092             }
00093         }
00094 
00095         if (type.IsScalar()) {
00096             
00097             XPTCVariant variant = new XPTCVariant();
00098             variant.type = type;
00099             variant.flags = 0;
00100             variant.ptr = IntPtr.Zero;
00101             Marshal.StructureToPtr(variant, buffer, false);
00102 
00103             IntPtr p;
00104             switch (type.tag) {
00105 
00106             case TypeTag.Int8:
00107             case TypeTag.Int16:
00108             case TypeTag.Int32:
00109             case TypeTag.UInt8:
00110             case TypeTag.UInt16:
00111             case TypeTag.UInt32:
00112             case TypeTag.Char:
00113             case TypeTag.WChar:
00114                 Marshal.WriteInt32(buffer, (Int32)arg);
00115                 break;
00116 
00117             case TypeTag.UInt64:
00118             case TypeTag.Int64:
00119                 Marshal.WriteInt64(buffer, (Int64)arg);
00120                 break;
00121 
00122             case TypeTag.Bool:
00123                 bool b = (bool)arg;
00124                 Marshal.WriteInt32(buffer, b ? 1 : 0);
00125                 break;
00126 
00127             case TypeTag.Float:
00128                 float[] f = new float[] { (float)arg };
00129                 Marshal.Copy(f, 0, buffer, 1);
00130                 break;
00131             case TypeTag.Double:
00132                 double[] d = new double[] { (double)arg };
00133                 Marshal.Copy(d, 0, buffer, 1);
00134                 break;
00135 
00136             case TypeTag.String:
00137                 Marshal.WriteIntPtr(buffer, 
00138                             Marshal.StringToCoTaskMemAnsi((string)arg));
00139                 break;
00140             case TypeTag.WString:
00141                 Marshal.WriteIntPtr(buffer, 
00142                             Marshal.StringToCoTaskMemUni((string)arg));
00143                 break;
00144 
00145             default:
00146                 msg = String.Format("{0}: type {1} not supported",
00147                                     param.Name(), type.tag.ToString());
00148                 throw new Exception(msg);
00149             }
00150 
00151             Console.WriteLine("{0} @ {1:X2}", param.Name(),
00152                               buffer.ToInt32());
00153             return;
00154         }
00155 
00156         if (type.tag == TypeTag.Interface) {
00157             Guid iid = param.GetIID();
00158             Console.WriteLine("{0} is interface {1}",
00159                               param.Name(), iid);
00160             Marshal.WriteIntPtr(buffer, CLRWrapper.Wrap(arg, ref iid));
00161             Console.WriteLine("{0} @ {1:X2}", param.Name(),
00162                               buffer.ToInt32());
00163             return;
00164         }
00165 
00166         msg = String.Format("{0} type {1} not yet supported ",
00167                             param.Name(), type.tag.ToString());
00168         throw new Exception(msg);
00169     }
00170 
00171     [DllImport("xpcom-dotnet.so")]
00172     public static extern IntPtr WrapCLRObject(IntPtr obj, Guid id);
00173 
00174     [DllImport("xpcom-dotnet.so")]
00175     static extern IntPtr typeinfo_WrapUnicode(IntPtr str,
00176                                               UInt32 length);
00177 
00178     [DllImport("xpcom-dotnet.so")]
00179     static extern void typeinfo_FreeWrappedUnicode(IntPtr str);
00180 
00181     static IntPtr MarshalArgs(MethodDescriptor desc, object[] args)
00182     {
00183         if (args.Length != desc.args.Length) {
00184             string msg = String.Format("{0} needs {1} args, {2} passed",
00185                                        desc.name, desc.args.Length, 
00186                                        args.Length);
00187             throw new Exception(msg);
00188         }
00189 
00190         int variantsz = 16; /* sizeof(nsXPTCVariant) */
00191         int size = variantsz * args.Length;
00192         IntPtr argbuf = Marshal.AllocCoTaskMem(size);
00193 
00194         for (int i = 0; i < args.Length; i++) {
00195             ParamDescriptor param = desc.args[i];
00196             IntPtr current = (IntPtr)(argbuf.ToInt32() + variantsz * i);
00197             object arg = args[i];
00198 
00199             MarshalOneArg(param, arg, current);
00200         }
00201 
00202         return argbuf;
00203     }
00204 
00205     static void FreeOneMarshalledArg(ParamDescriptor param, IntPtr buffer)
00206     {
00207     }
00208 
00209     static void DemarshalArgs(MethodDescriptor desc,
00210                               IntPtr argbuf)
00211     {
00212         int variantsz = Marshal.SizeOf(typeof(XPTCVariant));
00213         for (int i = 0; i < desc.args.Length; i++) {
00214             ParamDescriptor param = desc.args[i];
00215             IntPtr current = (IntPtr)(argbuf.ToInt32() + variantsz * i);
00216             FreeOneMarshalledArg(param, current);
00217         }
00218         Marshal.FreeCoTaskMem(argbuf);
00219     }
00220 
00221     public static int XPTC_InvokeByIndexSafe(IntPtr that, Int32 index,
00222                                              UInt32 argCount, IntPtr args)
00223     {
00224         Console.WriteLine("XPTC_IBI: {0:X2}:{1}({2}:{3:X2})",
00225                           that.ToInt32(), index, argCount, args.ToInt32());
00226         return XPTC_InvokeByIndex(that, index, argCount, args);
00227     }
00228 
00229     [DllImport("libxpcom.so")]
00230     static extern int XPTC_InvokeByIndex(IntPtr that, Int32 methodIndex,
00231                                          UInt32 argCount,
00232                                          IntPtr args);
00233 
00234     public static object Invoke(IntPtr that, string iface,
00235                                 string method, params object[] args)
00236     {
00237         return Invoke(that, TypeInfo.GetMethodData(iface, method), args);
00238     }
00239 
00240     public static object Invoke(IntPtr that, string iface,
00241                                 int method, params object[] args)
00242     {
00243         return Invoke(that, TypeInfo.GetMethodData(iface, method), args);
00244     }
00245 
00246     public static object Invoke(IntPtr that, MethodDescriptor desc,
00247                                 params object[] args)
00248     {
00249         IntPtr argbuf = MarshalArgs(desc, args);
00250         int res = XPTC_InvokeByIndex(that, desc.index,
00251                                      (UInt32)args.Length, argbuf);
00252         DemarshalArgs(desc, argbuf);
00253         if (res != 0) {
00254             throw new Exception(String.Format("XPCOM Error: {0:X2}",
00255                                               res));
00256         }
00257         return null;
00258     }
00259 }
00260 
00261 } // namespace Mozilla.XPCOM