зеркало из https://github.com/mozilla/gecko-dev.git
531 строка
16 KiB
C#
531 строка
16 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using Mozilla.XPCOM;
|
|
|
|
namespace Mozilla.XPCOM {
|
|
|
|
/* This doesn't need to be public, but making it 'internal' causes stress with
|
|
* TypeDescriptor.op_Implicit(XPTType). */
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct XPTType
|
|
{
|
|
public const byte FlagMask = 0xE0;
|
|
public const byte TagMask = 0x1F;
|
|
public byte prefix;
|
|
public byte arg1;
|
|
public byte arg2;
|
|
public byte padding;
|
|
public UInt16 arg3;
|
|
|
|
static public implicit operator XPTType(TypeInfo.TypeDescriptor td)
|
|
{
|
|
XPTType t = new XPTType();
|
|
t.prefix = (byte) ((byte)td.flags | (byte)td.tag);
|
|
t.arg1 = td.arg1;
|
|
t.arg2 = td.arg2;
|
|
t.arg3 = td.arg3;
|
|
return t;
|
|
}
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
struct XPTParamDescriptor
|
|
{
|
|
public byte param_flags;
|
|
public byte padding1;
|
|
public XPTType type;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]
|
|
struct XPTMethodDescriptor
|
|
{
|
|
public String name;
|
|
public IntPtr args; /* XPTParamDescriptor */
|
|
public IntPtr result; /* XPTParamDescriptor */
|
|
public byte flags;
|
|
public byte numArgs;
|
|
}
|
|
|
|
public class TypeInfo
|
|
{
|
|
[Flags]
|
|
public enum TypeFlags : byte
|
|
{
|
|
Pointer = 0x80, UniquePointer = 0x40, Reference = 0x20
|
|
}
|
|
|
|
public enum TypeTag : byte
|
|
{
|
|
Int8 = 0, Int16 = 1, Int32 = 2, Int64 = 3,
|
|
UInt8 = 4, UInt16 = 5, UInt32 = 6, UInt64 = 7,
|
|
Float = 8, Double = 9, Bool = 10, Char = 11,
|
|
WChar = 12, Void = 13, NSIdPtr = 14, AString = 15,
|
|
String = 16, WString = 17, Interface = 18, InterfaceIs = 19,
|
|
Array = 20, StringSizeIs = 21, WStringSizeIs = 22, UTF8String = 23,
|
|
CString = 24, AString_dup = 25
|
|
}
|
|
|
|
public struct TypeDescriptor
|
|
{
|
|
public TypeFlags flags;
|
|
public TypeTag tag;
|
|
public byte arg1;
|
|
public byte arg2;
|
|
public UInt16 arg3;
|
|
|
|
public override string ToString()
|
|
{
|
|
string res = String.Empty;
|
|
if ((Int32)flags != 0)
|
|
res = "[" + flags.ToString() + "]";
|
|
res += tag.ToString();
|
|
return res;
|
|
}
|
|
|
|
public bool IsScalar()
|
|
{
|
|
if (tag <= TypeTag.WChar ||
|
|
tag == TypeTag.String || tag == TypeTag.WString) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static public implicit operator TypeDescriptor(XPTType t)
|
|
{
|
|
TypeDescriptor td = new TypeInfo.TypeDescriptor();
|
|
td.flags = (TypeFlags)(t.prefix & XPTType.FlagMask);
|
|
td.tag = (TypeTag)(t.prefix & XPTType.TagMask);
|
|
td.arg1 = t.arg1;
|
|
td.arg2 = t.arg2;
|
|
td.arg3 = t.arg3;
|
|
return td;
|
|
}
|
|
|
|
public Type AsCLRType()
|
|
{
|
|
switch (tag) {
|
|
case TypeTag.Int8:
|
|
return typeof(sbyte);
|
|
case TypeTag.Int16:
|
|
return typeof(Int16);
|
|
case TypeTag.Int32:
|
|
return typeof(Int32);
|
|
case TypeTag.Int64:
|
|
return typeof(Int64);
|
|
|
|
case TypeTag.UInt8:
|
|
return typeof(byte);
|
|
case TypeTag.UInt16:
|
|
return typeof(UInt16);
|
|
case TypeTag.UInt32:
|
|
return typeof(UInt32);
|
|
case TypeTag.UInt64:
|
|
return typeof(UInt64);
|
|
|
|
case TypeTag.Float:
|
|
return typeof(Single);
|
|
case TypeTag.Double:
|
|
return typeof(Double);
|
|
|
|
case TypeTag.Bool:
|
|
return typeof(bool);
|
|
|
|
case TypeTag.String:
|
|
return typeof(string);
|
|
case TypeTag.WString:
|
|
return typeof(string);
|
|
|
|
case TypeTag.Interface:
|
|
return typeof(object);
|
|
case TypeTag.InterfaceIs:
|
|
return typeof(object);
|
|
|
|
case TypeTag.Char:
|
|
return typeof(byte);
|
|
case TypeTag.WChar:
|
|
return typeof(char);
|
|
|
|
case TypeTag.NSIdPtr:
|
|
return Type.GetType("System.Guid&");
|
|
// return typeof(Guid).MakeByRefType(); NET_2_0
|
|
|
|
default:
|
|
string msg = String.Format("type {0} not yet supported ",
|
|
tag.ToString());
|
|
|
|
throw new Exception(msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Flags]
|
|
public enum ParamFlags : byte
|
|
{
|
|
In = 0x80, Out = 0x40, RetVal = 0x20, Shared = 0x10, Dipper = 0x08
|
|
}
|
|
|
|
public struct ParamDescriptor
|
|
{
|
|
public MethodDescriptor method;
|
|
public int index;
|
|
public ParamFlags flags;
|
|
public TypeDescriptor type;
|
|
|
|
public Type GetCLRType()
|
|
{
|
|
Type t = type.AsCLRType();
|
|
if (IsOut() && !IsRetVal()) {
|
|
Type reft = System.Type.GetType(t.FullName + "&");
|
|
Console.WriteLine("{0} -> {1}", t.FullName, reft.FullName);
|
|
t = reft;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return "[" + flags.ToString() + "] " + type.ToString();
|
|
}
|
|
|
|
public string Name()
|
|
{
|
|
return method.Name() + ":" + index;
|
|
}
|
|
|
|
public bool IsOut()
|
|
{
|
|
return (flags & ParamFlags.Out) != 0;
|
|
}
|
|
|
|
public bool IsIn()
|
|
{
|
|
return (flags & ParamFlags.In) != 0;
|
|
}
|
|
|
|
public bool IsRetVal()
|
|
{
|
|
return (flags & ParamFlags.RetVal) != 0;
|
|
}
|
|
|
|
public Guid GetIID()
|
|
{
|
|
if (type.tag != TypeTag.Interface) {
|
|
throw new Exception(String.Format("{0} not an interface type",
|
|
this));
|
|
}
|
|
|
|
Guid iid;
|
|
int res;
|
|
res = typeinfo_GetIIDForParam(method.ifaceName, method.index,
|
|
index, out iid);
|
|
if (res != 0) {
|
|
throw new
|
|
Exception(String.Format("GetIIDForParam failed: {0:X8}",
|
|
res));
|
|
}
|
|
return iid;
|
|
}
|
|
|
|
public string GetInterfaceName()
|
|
{
|
|
return TypeInfo.NameForIID(GetIID());
|
|
}
|
|
}
|
|
|
|
[Flags]
|
|
public enum MethodFlags : byte
|
|
{
|
|
Getter = 0x80, Setter = 0x40, NotXPCOM = 0x20, Constructor = 0x10,
|
|
Hidden = 0x08
|
|
}
|
|
|
|
public class MethodDescriptor
|
|
{
|
|
public int index;
|
|
public String name;
|
|
public ParamDescriptor[] args;
|
|
public ParamDescriptor result;
|
|
public Type[] argTypes;
|
|
public Type resultType;
|
|
public MethodFlags flags;
|
|
public String ifaceName;
|
|
|
|
public bool IsVisible()
|
|
{
|
|
return (flags & (MethodFlags.Hidden | MethodFlags.NotXPCOM)) == 0;
|
|
}
|
|
|
|
public bool IsSetter()
|
|
{
|
|
return (flags & MethodFlags.Setter) != 0;
|
|
}
|
|
|
|
public bool IsGetter()
|
|
{
|
|
return (flags & MethodFlags.Getter) != 0;
|
|
}
|
|
|
|
public string Name()
|
|
{
|
|
return ifaceName + ":" + name + "(" + index + ")";
|
|
}
|
|
|
|
public Type FindResultType()
|
|
{
|
|
for (int i = 0; i < args.Length; i++) {
|
|
if (args[i].IsRetVal())
|
|
return args[i].GetCLRType();
|
|
}
|
|
return typeof(void);
|
|
}
|
|
|
|
public void BuildArgTypes()
|
|
{
|
|
if (!IsVisible()) {
|
|
argTypes = new Type[] { };
|
|
return;
|
|
}
|
|
|
|
if (resultType != typeof(void))
|
|
argTypes = new Type[args.Length - 1];
|
|
else
|
|
argTypes = new Type[args.Length];
|
|
int j = 0;
|
|
for (int i = 0; i < args.Length; i++) {
|
|
if (args[i].IsRetVal())
|
|
continue;
|
|
argTypes[j++] = args[i].GetCLRType();
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
string res = String.Empty;
|
|
if (flags != 0)
|
|
res = "[" + flags.ToString() + "] ";
|
|
res += result.ToString() + " " + name + "(";
|
|
for (int i = 0; i < args.Length; i++) {
|
|
if (i != 0)
|
|
res += ", ";
|
|
res += args[i].ToString();
|
|
}
|
|
res += ")";
|
|
return res;
|
|
}
|
|
}
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
static extern int typeinfo_GetAllMethodData(String iface,
|
|
out IntPtr infos,
|
|
out UInt16 count);
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
static extern int typeinfo_GetMethodData(String iface, int method,
|
|
out IntPtr info);
|
|
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
static extern int typeinfo_GetMethodData_byname(String iface,
|
|
String method,
|
|
out UInt16 index,
|
|
out IntPtr info);
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
static extern int typeinfo_GetMethodData_iid_index(ref Guid iid, int index,
|
|
out IntPtr xptinfo);
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
static extern int typeinfo_GetIIDForParam(String iface, int method,
|
|
int param, out Guid iid);
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
static extern int typeinfo_GetNameForIID(ref Guid iid, out String name);
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
public static extern IntPtr typeinfo_EnumerateInterfacesStart();
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
public static extern String typeinfo_EnumerateInterfacesNext(IntPtr e);
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
public static extern void typeinfo_EnumerateInterfacesStop(IntPtr e);
|
|
|
|
[DllImport("xpcom-dotnet.so")]
|
|
public static extern int typeinfo_GetParentInfo(String name,
|
|
out String parentName,
|
|
out UInt16 methodCount);
|
|
|
|
public static String GetParentInfo(String name, out UInt16 methodCount)
|
|
{
|
|
String parentName;
|
|
int res = typeinfo_GetParentInfo(name, out parentName,
|
|
out methodCount);
|
|
if (res != 0) {
|
|
throw new Exception(String.Format("GetParentInfo({0}) " +
|
|
"failed: {1:X8}", name, res));
|
|
}
|
|
return parentName;
|
|
}
|
|
|
|
static ParamDescriptor BuildParamDescriptor(IntPtr paramptr, int index,
|
|
MethodDescriptor method)
|
|
{
|
|
XPTParamDescriptor xptpd = (XPTParamDescriptor)
|
|
Marshal.PtrToStructure(paramptr, typeof(XPTParamDescriptor));
|
|
ParamDescriptor pd = new ParamDescriptor();
|
|
pd.method = method;
|
|
pd.index = index;
|
|
pd.flags = (ParamFlags) xptpd.param_flags;
|
|
pd.type = xptpd.type;
|
|
return pd;
|
|
}
|
|
|
|
static ParamDescriptor BuildRetValDescriptor(IntPtr paramptr,
|
|
MethodDescriptor method)
|
|
{
|
|
return BuildParamDescriptor(paramptr, -1, method);
|
|
}
|
|
|
|
static ParamDescriptor[] BuildParamDescriptorArray(IntPtr paramptr,
|
|
int count,
|
|
MethodDescriptor method)
|
|
{
|
|
ParamDescriptor[] parr = new ParamDescriptor[count];
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
parr[i] = BuildParamDescriptor(paramptr, i, method);
|
|
paramptr = (IntPtr)(paramptr.ToInt32() + 8);
|
|
}
|
|
return parr;
|
|
}
|
|
|
|
static MethodDescriptor ConvertMethodDescriptor(IntPtr xptinfo,
|
|
string ifaceName,
|
|
int index)
|
|
{
|
|
XPTMethodDescriptor info;
|
|
info = (XPTMethodDescriptor)
|
|
Marshal.PtrToStructure(xptinfo, typeof(XPTMethodDescriptor));
|
|
MethodDescriptor meth = new MethodDescriptor();
|
|
meth.ifaceName = ifaceName;
|
|
meth.index = index;
|
|
meth.name = System.Char.ToUpper(info.name[0]) + info.name.Substring(1);
|
|
meth.flags = (MethodFlags)info.flags;
|
|
meth.args = BuildParamDescriptorArray(info.args, info.numArgs, meth);
|
|
meth.result = BuildRetValDescriptor(info.result, meth);
|
|
if (meth.IsVisible()) {
|
|
meth.resultType = meth.FindResultType();
|
|
meth.BuildArgTypes();
|
|
}
|
|
return meth;
|
|
}
|
|
|
|
static public MethodDescriptor[] GetMethodData(string ifaceName)
|
|
{
|
|
IntPtr buffer;
|
|
UInt16 count;
|
|
|
|
int res = typeinfo_GetAllMethodData(ifaceName, out buffer, out count);
|
|
if (res != 0) {
|
|
throw new Exception(String.Format("GetAllMethodData({0}) " +
|
|
"failed: {1:X8}",
|
|
ifaceName, res));
|
|
}
|
|
|
|
MethodDescriptor[] methods = new MethodDescriptor[count];
|
|
|
|
for (int i = 0; i < (UInt16)count; i++) {
|
|
IntPtr infoptr = Marshal.ReadIntPtr(buffer, i *
|
|
Marshal.SizeOf(typeof(IntPtr)));
|
|
try {
|
|
methods[i] = ConvertMethodDescriptor(infoptr, ifaceName, i);
|
|
} catch (Exception e) {
|
|
Console.WriteLine("skipping {0}[{1}]: {2}",
|
|
ifaceName, i, e.Message);
|
|
}
|
|
}
|
|
|
|
if (count > 0)
|
|
Marshal.FreeCoTaskMem(buffer);
|
|
|
|
return methods;
|
|
}
|
|
|
|
static public MethodDescriptor GetMethodData(Guid iid, int index)
|
|
{
|
|
IntPtr xptinfo;
|
|
int res = typeinfo_GetMethodData_iid_index(ref iid, index,
|
|
out xptinfo);
|
|
if (res != 0) {
|
|
throw new Exception(String.Format("GetMethodData({0}.{1}) " +
|
|
"failed: {2:X8}",
|
|
iid, index, res));
|
|
}
|
|
|
|
String name;
|
|
res = typeinfo_GetNameForIID(ref iid, out name);
|
|
if (res != 0) {
|
|
throw new Exception(String.Format("GetNameForIID failed: {0:X8}",
|
|
res));
|
|
}
|
|
return ConvertMethodDescriptor(xptinfo, name, index);
|
|
}
|
|
|
|
static public String NameForIID(Guid iid)
|
|
{
|
|
String name;
|
|
int res = typeinfo_GetNameForIID(ref iid, out name);
|
|
if (res != 0) {
|
|
throw new
|
|
Exception(String.Format("GetNameForIID failed: {0:X8}",
|
|
res));
|
|
}
|
|
return name;
|
|
}
|
|
|
|
static public Type TypeForIID(Guid iid)
|
|
{
|
|
String ifaceName = "Mozilla.XPCOM.Interfaces." + NameForIID(iid) +
|
|
",Mozilla.XPCOM.Interfaces";
|
|
return System.Type.GetType(ifaceName);
|
|
}
|
|
|
|
static public MethodDescriptor GetMethodData(string ifaceName,
|
|
string methodName)
|
|
{
|
|
IntPtr xptinfo;
|
|
UInt16 index;
|
|
int res = typeinfo_GetMethodData_byname(ifaceName, methodName,
|
|
out index, out xptinfo);
|
|
|
|
if (res != 0) {
|
|
throw new Exception(String.Format("GetMethodData({0}.{1}) " +
|
|
"failed: {2:X8}",
|
|
ifaceName, methodName, res));
|
|
}
|
|
|
|
// Console.WriteLine("{0} is index {1}", methodName, index);
|
|
|
|
return ConvertMethodDescriptor(xptinfo, ifaceName, (int)index);
|
|
}
|
|
|
|
static public MethodDescriptor GetMethodData(String ifaceName,
|
|
int methodIndex)
|
|
{
|
|
IntPtr xptinfo;
|
|
|
|
int res = typeinfo_GetMethodData(ifaceName, methodIndex, out xptinfo);
|
|
|
|
if (xptinfo == IntPtr.Zero) {
|
|
throw new Exception(String.Format("GetMethodData({0}:{1}) failed:" +
|
|
" {2:X8}",
|
|
ifaceName, methodIndex, res));
|
|
}
|
|
|
|
return ConvertMethodDescriptor(xptinfo, ifaceName, methodIndex);
|
|
}
|
|
}
|
|
|
|
} // namespace Mozilla.XPCOM
|