зеркало из https://github.com/mozilla/gecko-dev.git
initial import of monoconnect^Wxpcom-dotnet^Wextensions/mono code -- not working, not done, not useful to you, not part of the build
This commit is contained in:
Родитель
4429a9bd0e
Коммит
47bcc65e52
|
@ -0,0 +1,16 @@
|
|||
CXXFLAGS = -shared -g -fPIC -fno-rtti $(shell pkg-config --cflags mozilla-xpcom)
|
||||
LDFLAGS = $(shell pkg-config --libs mozilla-xpcom)
|
||||
|
||||
all: xpcom-dotnet.so xpcom-dotnet.dll
|
||||
|
||||
MCS ?= mcs
|
||||
MCSFLAGS ?= /debug
|
||||
|
||||
xpcom-dotnet.so: typeinfo.cpp xpcom-core.cpp wrapped-clr.cpp
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
xpcom-dotnet.dll: typeinfo.cs xptinvoke.cs wrapped-clr.cs components.cs proxy-generator.cs interface-generator.cs
|
||||
$(MCS) $(MCSFLAGS) -unsafe /t:library /out:$@ $^
|
||||
|
||||
clean:
|
||||
rm -f xpcom-dotnet.{so,dll}
|
|
@ -0,0 +1,95 @@
|
|||
using System;
|
||||
using Mozilla.XPCOM;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mozilla.XPCOM {
|
||||
|
||||
public class Components
|
||||
{
|
||||
[DllImport("xpcom-dotnet.so")]
|
||||
static extern int StartXPCOM(out IntPtr srvmgr);
|
||||
|
||||
static IntPtr serviceManager = IntPtr.Zero;
|
||||
|
||||
public static IntPtr ServiceManager {
|
||||
get {
|
||||
return serviceManager;
|
||||
}
|
||||
}
|
||||
|
||||
static void RegisterAppDomainHooks()
|
||||
{
|
||||
AppDomain.CurrentDomain.TypeResolve +=
|
||||
new ResolveEventHandler(TypeResolve);
|
||||
AppDomain.CurrentDomain.AssemblyResolve +=
|
||||
new ResolveEventHandler(AssemblyResolve);
|
||||
Console.WriteLine("XPCOM AppDomain hooks registered.");
|
||||
}
|
||||
|
||||
static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
Console.WriteLine("Resolving: {0}", args.Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static AssemblyBuilder ProxyAssembly {
|
||||
get {
|
||||
return ProxyGenerator.ProxyAssembly;
|
||||
}
|
||||
}
|
||||
|
||||
static Assembly TypeResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
if (args.Name.StartsWith("Mozilla.XPCOM.Proxies.")) {
|
||||
ProxyGenerator gen = new ProxyGenerator(args.Name);
|
||||
return gen.Generate();
|
||||
}
|
||||
|
||||
#if NOTYET
|
||||
if (args.Name.StartsWith("Mozilla.XPCOM.Interfaces.")) {
|
||||
InterfaceGenerator gen = new InterfaceGenerator(args.Name);
|
||||
return gen.Generate();
|
||||
}
|
||||
#endif
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
if (serviceManager != IntPtr.Zero)
|
||||
return;
|
||||
|
||||
int res = StartXPCOM(out serviceManager);
|
||||
if (res != 0) {
|
||||
throw new Exception(String.Format("StartXPCOM failed: {0:X2}",
|
||||
res));
|
||||
}
|
||||
|
||||
RegisterAppDomainHooks();
|
||||
}
|
||||
|
||||
[DllImport("test.so", EntryPoint="GetImpl")]
|
||||
public static extern IntPtr GetTestImpl();
|
||||
|
||||
public static object CreateInstance(string contractId, Type iface)
|
||||
{
|
||||
String typeName = iface.FullName;
|
||||
String proxyName = typeName.Replace(".Interfaces.", ".Proxies.");
|
||||
Console.WriteLine("Need proxy class {0} for {1}", proxyName, typeName);
|
||||
Type proxyType = System.Type.GetType(proxyName);
|
||||
if (contractId == "@off.net/test-component;1") {
|
||||
ConstructorInfo ctor =
|
||||
proxyType.GetConstructor(BindingFlags.NonPublic |
|
||||
BindingFlags.Instance,
|
||||
null, new Type[1] { typeof(IntPtr) },
|
||||
null);
|
||||
return ctor.Invoke(new object[] { GetTestImpl() });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Mozilla.XPCOM;
|
||||
using MethodDescriptor = Mozilla.XPCOM.TypeInfo.MethodDescriptor;
|
||||
using TypeTag = Mozilla.XPCOM.TypeInfo.TypeTag;
|
||||
using ParamFlags = Mozilla.XPCOM.TypeInfo.ParamFlags;
|
||||
|
||||
namespace Mozilla.XPCOM
|
||||
{
|
||||
|
||||
class InterfaceGenerator
|
||||
{
|
||||
static ModuleBuilder module;
|
||||
|
||||
static InterfaceGenerator()
|
||||
{
|
||||
AssemblyName an = new AssemblyName();
|
||||
an.Version = new Version(1, 0, 0, 0);
|
||||
an.Name = "Mozilla.XPCOM.Interfaces";
|
||||
|
||||
AppDomain curDom = AppDomain.CurrentDomain;
|
||||
AssemblyBuilder ab =
|
||||
curDom.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
|
||||
|
||||
module = ab.DefineDynamicModule(an.Name);
|
||||
}
|
||||
|
||||
String typeName;
|
||||
TypeBuilder tb;
|
||||
|
||||
internal InterfaceGenerator(String name)
|
||||
{
|
||||
typeName = name;
|
||||
}
|
||||
|
||||
const PropertyAttributes PROPERTY_ATTRS = PropertyAttributes.None;
|
||||
const MethodAttributes METHOD_ATTRS = MethodAttributes.Public |
|
||||
MethodAttributes.Abstract | MethodAttributes.Virtual;
|
||||
PropertyBuilder lastProperty = null;
|
||||
|
||||
Type FixupInterfaceType(TypeInfo.ParamDescriptor desc)
|
||||
{
|
||||
try {
|
||||
return TypeInfo.TypeForIID(desc.GetIID());
|
||||
} catch (Exception e) {
|
||||
// Console.WriteLine(e);
|
||||
return typeof(object);
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateInterfaceMethod(TypeInfo.MethodDescriptor desc)
|
||||
{
|
||||
if (desc == null || !desc.IsVisible())
|
||||
return;
|
||||
|
||||
MethodAttributes methodAttrs = METHOD_ATTRS;
|
||||
|
||||
String methodName = desc.name;
|
||||
if (desc.IsGetter()) {
|
||||
methodName = "get_" + desc.name;
|
||||
methodAttrs |= MethodAttributes.SpecialName;
|
||||
} else if (desc.IsSetter()) {
|
||||
methodName = "set_" + desc.name;
|
||||
methodAttrs |= MethodAttributes.SpecialName;
|
||||
}
|
||||
|
||||
// Fix up interface types in parameters
|
||||
Type ret = desc.resultType;
|
||||
if (ret == typeof(object))
|
||||
ret = FixupInterfaceType(desc.args[desc.args.Length - 1]);
|
||||
Type[] argTypes = (Type[])desc.argTypes.Clone();
|
||||
for (int i = 0; i < argTypes.Length; i++) {
|
||||
if (argTypes[i] == typeof(object))
|
||||
argTypes[i] = FixupInterfaceType(desc.args[i]);
|
||||
}
|
||||
MethodBuilder meth = tb.DefineMethod(methodName, methodAttrs, ret,
|
||||
desc.argTypes);
|
||||
|
||||
if (desc.IsSetter()) {
|
||||
if (lastProperty != null && lastProperty.Name == desc.name) {
|
||||
lastProperty.SetSetMethod(meth);
|
||||
} else {
|
||||
tb.DefineProperty(desc.name, PROPERTY_ATTRS, desc.resultType,
|
||||
new Type[0]).SetSetMethod(meth);
|
||||
}
|
||||
lastProperty = null;
|
||||
} else if (desc.IsGetter()) {
|
||||
lastProperty = tb.DefineProperty(desc.name, PROPERTY_ATTRS,
|
||||
desc.resultType, new Type[0]);
|
||||
lastProperty.SetGetMethod(meth);
|
||||
} else {
|
||||
lastProperty = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal Assembly Generate()
|
||||
{
|
||||
if (module.GetType(typeName) != null)
|
||||
return module.Assembly;
|
||||
|
||||
String ifaceName = typeName.Replace("Mozilla.XPCOM.Interfaces.", "");
|
||||
TypeInfo.MethodDescriptor[] descs =
|
||||
TypeInfo.GetMethodData(ifaceName);
|
||||
|
||||
ushort inheritedMethodCount;
|
||||
String parentName = TypeInfo.GetParentInfo(ifaceName,
|
||||
out inheritedMethodCount);
|
||||
Type parentType;
|
||||
|
||||
if (parentName != null) {
|
||||
parentName = "Mozilla.XPCOM.Interfaces." + parentName;
|
||||
parentType = module.Assembly.GetType(parentName);
|
||||
if (parentType == null) {
|
||||
InterfaceGenerator gen = new InterfaceGenerator(parentName);
|
||||
parentType = gen.Generate().GetType(parentName);
|
||||
}
|
||||
} else {
|
||||
parentType = typeof(object);
|
||||
}
|
||||
|
||||
tb = module.DefineType(typeName,
|
||||
TypeAttributes.Public | TypeAttributes.Interface,
|
||||
parentType);
|
||||
|
||||
for (int i = inheritedMethodCount; i < descs.Length; i++) {
|
||||
if (descs[i] != null)
|
||||
GenerateInterfaceMethod(descs[i]);
|
||||
}
|
||||
|
||||
tb.CreateType();
|
||||
|
||||
return module.Assembly;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,392 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Mozilla.XPCOM;
|
||||
using MethodDescriptor = Mozilla.XPCOM.TypeInfo.MethodDescriptor;
|
||||
using TypeTag = Mozilla.XPCOM.TypeInfo.TypeTag;
|
||||
using ParamFlags = Mozilla.XPCOM.TypeInfo.ParamFlags;
|
||||
|
||||
namespace Mozilla.XPCOM
|
||||
{
|
||||
|
||||
public class BaseProxy
|
||||
{
|
||||
protected IntPtr thisptr;
|
||||
protected BaseProxy(IntPtr ptr) { thisptr = ptr; }
|
||||
}
|
||||
|
||||
class ProxyGenerator
|
||||
{
|
||||
void EmitPtrAndFlagsStore(int argnum, IntPtr ptr, sbyte flags)
|
||||
{
|
||||
//= bufLocal[argnum].ptr = ptr;
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 8);
|
||||
ilg.Emit(OpCodes.Add);
|
||||
ilg.Emit(OpCodes.Ldc_I4, ptr.ToInt32());
|
||||
ilg.Emit(OpCodes.Stind_I4);
|
||||
|
||||
//= bufLocal[argnum].flags = flags;
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 13);
|
||||
ilg.Emit(OpCodes.Add);
|
||||
ilg.Emit(OpCodes.Ldc_I4, (Int32)flags);
|
||||
ilg.Emit(OpCodes.Stind_I1);
|
||||
}
|
||||
|
||||
void EmitTypeStore(TypeInfo.TypeDescriptor t, int argnum)
|
||||
{
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 12);
|
||||
ilg.Emit(OpCodes.Add);
|
||||
ilg.Emit(OpCodes.Ldc_I4, (Int32)t.tag);
|
||||
ilg.Emit(OpCodes.Stind_I4);
|
||||
}
|
||||
|
||||
void EmitComputeBufferLoc(int argnum)
|
||||
{
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE);
|
||||
ilg.Emit(OpCodes.Add);
|
||||
}
|
||||
|
||||
void EmitPrepareArgStore(int argnum)
|
||||
{
|
||||
EmitComputeBufferLoc(argnum);
|
||||
EmitLoadArg(argnum);
|
||||
}
|
||||
|
||||
void EmitLoadArg(int argnum)
|
||||
{
|
||||
switch (argnum) {
|
||||
case 0:
|
||||
ilg.Emit(OpCodes.Ldarg_1);
|
||||
break;
|
||||
case 1:
|
||||
ilg.Emit(OpCodes.Ldarg_2);
|
||||
break;
|
||||
case 2:
|
||||
ilg.Emit(OpCodes.Ldarg_3);
|
||||
break;
|
||||
default:
|
||||
if (argnum < 254)
|
||||
ilg.Emit(OpCodes.Ldarg_S, argnum + 1);
|
||||
else
|
||||
ilg.Emit(OpCodes.Ldarg, argnum + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EmitLoadReturnSlot_1(int slotnum)
|
||||
{
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldc_I4, (slotnum - 1) * VARIANT_SIZE);
|
||||
ilg.Emit(OpCodes.Add);
|
||||
ilg.Emit(OpCodes.Ldind_I4);
|
||||
}
|
||||
|
||||
void EmitOutParamPrep(TypeInfo.TypeDescriptor type, int argnum)
|
||||
{
|
||||
ilg.Emit(OpCodes.Nop);
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 13);
|
||||
ilg.Emit(OpCodes.Add);
|
||||
ilg.Emit(OpCodes.Ldc_I4, 1); // PTR_IS_DATA
|
||||
ilg.Emit(OpCodes.Stind_I1);
|
||||
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 8); // offsetof(ptr)
|
||||
ilg.Emit(OpCodes.Add);
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldc_I4, argnum * VARIANT_SIZE + 0); // offsetof(val)
|
||||
ilg.Emit(OpCodes.Add);
|
||||
ilg.Emit(OpCodes.Stind_I4); /* XXX 64-bitness! */
|
||||
}
|
||||
|
||||
void EmitProxyConstructor()
|
||||
{
|
||||
ConstructorBuilder ctor =
|
||||
tb.DefineConstructor(MethodAttributes.Family,
|
||||
CallingConventions.Standard,
|
||||
new Type[1] { typeof(IntPtr) });
|
||||
ILGenerator ilg = ctor.GetILGenerator();
|
||||
ilg.Emit(OpCodes.Ldarg_0);
|
||||
ilg.Emit(OpCodes.Ldarg_1);
|
||||
ilg.Emit(OpCodes.Call, baseProxyCtor);
|
||||
ilg.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
const int VARIANT_SIZE = 16; // sizeof(XPTCVariant)
|
||||
|
||||
const PropertyAttributes PROPERTY_ATTRS = PropertyAttributes.None;
|
||||
|
||||
PropertyBuilder lastProperty;
|
||||
|
||||
Type FixupInterfaceType(TypeInfo.ParamDescriptor desc)
|
||||
{
|
||||
try {
|
||||
return TypeInfo.TypeForIID(desc.GetIID());
|
||||
} catch (Exception e) {
|
||||
// Console.WriteLine(e);
|
||||
return typeof(object);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe void GenerateProxyMethod(MethodDescriptor desc)
|
||||
{
|
||||
if (!desc.IsVisible()) {
|
||||
Console.WriteLine("HIDDEN: {0}", desc);
|
||||
return;
|
||||
}
|
||||
MethodAttributes methodAttrs =
|
||||
MethodAttributes.Public | MethodAttributes.Virtual;
|
||||
|
||||
String methodName = desc.name;
|
||||
if (desc.IsGetter()) {
|
||||
methodName = "get_" + desc.name;
|
||||
methodAttrs |= MethodAttributes.SpecialName;
|
||||
} else if (desc.IsSetter()) {
|
||||
methodName = "set_" + desc.name;
|
||||
methodAttrs |= MethodAttributes.SpecialName;
|
||||
}
|
||||
|
||||
// Fix up interface types in parameters
|
||||
Type ret = desc.resultType;
|
||||
if (ret == typeof(object))
|
||||
ret = FixupInterfaceType(desc.args[desc.args.Length - 1]);
|
||||
Type[] argTypes = (Type[])desc.argTypes.Clone();
|
||||
for (int i = 0; i < argTypes.Length; i++) {
|
||||
if (argTypes[i] == typeof(object))
|
||||
argTypes[i] = FixupInterfaceType(desc.args[i]);
|
||||
}
|
||||
MethodBuilder meth = tb.DefineMethod(methodName, methodAttrs, ret, argTypes);
|
||||
|
||||
ilg = meth.GetILGenerator();
|
||||
bufLocal = ilg.DeclareLocal(System.Type.GetType("System.Int32*"));
|
||||
LocalBuilder guidLocal = ilg.DeclareLocal(typeof(System.Guid));
|
||||
TypeInfo.ParamDescriptor[] args = desc.args;
|
||||
|
||||
Type marshalType = typeof(System.Runtime.InteropServices.Marshal);
|
||||
|
||||
// Marshal.AllocCoTaskMem(constify(argBufSize))
|
||||
int argCount = args.Length;
|
||||
int argBufSize = VARIANT_SIZE * args.Length;
|
||||
|
||||
ilg.Emit(OpCodes.Ldc_I4, argBufSize);
|
||||
ilg.Emit(OpCodes.Call, marshalType.GetMethod("AllocCoTaskMem"));
|
||||
ilg.Emit(OpCodes.Stloc, bufLocal);
|
||||
|
||||
for (int i = 0; i < argCount; i++) {
|
||||
TypeInfo.ParamDescriptor param = args[i];
|
||||
TypeInfo.TypeDescriptor type = param.type;
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
sbyte flags = 0;
|
||||
EmitTypeStore(type, i);
|
||||
|
||||
if (param.IsOut()) {
|
||||
EmitOutParamPrep(type, i);
|
||||
if (!param.IsIn())
|
||||
continue;
|
||||
}
|
||||
switch (type.tag) {
|
||||
case TypeTag.Int8:
|
||||
case TypeTag.Int16:
|
||||
case TypeTag.UInt8:
|
||||
case TypeTag.UInt16:
|
||||
case TypeTag.Char:
|
||||
case TypeTag.WChar:
|
||||
case TypeTag.UInt32:
|
||||
EmitPrepareArgStore(i);
|
||||
// XXX do I need to cast this?
|
||||
ilg.Emit(OpCodes.Castclass, typeof(Int32));
|
||||
ilg.Emit(OpCodes.Stind_I4);
|
||||
break;
|
||||
case TypeTag.Int32:
|
||||
EmitPrepareArgStore(i);
|
||||
ilg.Emit(OpCodes.Stind_I4);
|
||||
break;
|
||||
case TypeTag.NSIDPtr:
|
||||
EmitPrepareArgStore(i);
|
||||
ilg.Emit(OpCodes.Stind_I4); // XXX 64-bitness
|
||||
break;
|
||||
case TypeTag.String:
|
||||
EmitPrepareArgStore(i);
|
||||
// the string arg is now on the stack
|
||||
ilg.Emit(OpCodes.Call,
|
||||
marshalType.GetMethod("StringToCoTaskMemAnsi"));
|
||||
ilg.Emit(OpCodes.Stind_I4);
|
||||
break;
|
||||
case TypeTag.Interface:
|
||||
EmitPrepareArgStore(i);
|
||||
// MRP is the object passed as this arg
|
||||
ilg.Emit(OpCodes.Ldloca_S, guidLocal);
|
||||
ilg.Emit(OpCodes.Ldstr, param.GetIID().ToString());
|
||||
ilg.Emit(OpCodes.Call, guidCtor);
|
||||
ilg.Emit(OpCodes.Ldloca_S, guidLocal);
|
||||
// stack is now objarg, ref guid
|
||||
ilg.Emit(OpCodes.Call, typeof(CLRWrapper).GetMethod("Wrap"));
|
||||
// now stack has the IntPtr in position to be stored.
|
||||
ilg.Emit(OpCodes.Stind_I4);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
String msg = String.Format("{0}: type {1} not supported",
|
||||
param.Name(), type.tag.ToString());
|
||||
throw new Exception(msg);
|
||||
*/
|
||||
break;
|
||||
}
|
||||
EmitPtrAndFlagsStore(i, ptr, flags);
|
||||
}
|
||||
|
||||
//= (void)XPTC_InvokeByIndex(thisptr, desc.index, length, bufLocal);
|
||||
ilg.Emit(OpCodes.Ldarg_0);
|
||||
ilg.Emit(OpCodes.Ldfld, thisField);
|
||||
ilg.Emit(OpCodes.Ldc_I4, desc.index);
|
||||
ilg.Emit(OpCodes.Ldc_I4, args.Length);
|
||||
ilg.Emit(OpCodes.Ldloc_0);
|
||||
ilg.Emit(OpCodes.Call, typeof(Mozilla.XPCOM.Invoker).
|
||||
GetMethod("XPTC_InvokeByIndex",
|
||||
BindingFlags.Static | BindingFlags.NonPublic));
|
||||
ilg.Emit(OpCodes.Pop);
|
||||
|
||||
if (ret == typeof(string)) {
|
||||
ilg.Emit(OpCodes.Ldstr, "FAKE RETURN STRING");
|
||||
} else if (ret == typeof(object)) {
|
||||
ilg.Emit(OpCodes.Newobj,
|
||||
typeof(object).GetConstructor(new Type[0]));
|
||||
} else if (ret == typeof(int)) {
|
||||
EmitLoadReturnSlot_1(args.Length);
|
||||
} else if (ret == typeof(void)) {
|
||||
// Nothing
|
||||
} else {
|
||||
throw new Exception(String.Format("return type {0} not " +
|
||||
"supported yet",
|
||||
desc.result.type.tag));
|
||||
}
|
||||
|
||||
//= Marshal.FreeCoTaskMem(bufLocal);
|
||||
ilg.Emit(OpCodes.Ldloc, bufLocal);
|
||||
ilg.Emit(OpCodes.Call, marshalType.GetMethod("FreeCoTaskMem"));
|
||||
|
||||
ilg.Emit(OpCodes.Ret);
|
||||
|
||||
ilg = null;
|
||||
bufLocal = null;
|
||||
|
||||
if (desc.IsSetter()) {
|
||||
if (lastProperty != null && lastProperty.Name == desc.name) {
|
||||
lastProperty.SetSetMethod(meth);
|
||||
} else {
|
||||
tb.DefineProperty(desc.name, PROPERTY_ATTRS, desc.resultType,
|
||||
new Type[0]).SetSetMethod(meth);
|
||||
}
|
||||
lastProperty = null;
|
||||
} else if (desc.IsGetter()) {
|
||||
lastProperty = tb.DefineProperty(desc.name, PROPERTY_ATTRS,
|
||||
desc.resultType, new Type[0]);
|
||||
lastProperty.SetGetMethod(meth);
|
||||
} else {
|
||||
lastProperty = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static ModuleBuilder module;
|
||||
static AssemblyBuilder builder;
|
||||
static ConstructorInfo baseProxyCtor;
|
||||
static ConstructorInfo guidCtor;
|
||||
|
||||
internal static AssemblyBuilder ProxyAssembly {
|
||||
get { return builder; }
|
||||
}
|
||||
|
||||
static ProxyGenerator()
|
||||
{
|
||||
AssemblyName an = new AssemblyName();
|
||||
an.Version = new Version(1, 0, 0, 0);
|
||||
an.Name = "Mozilla.XPCOM.Proxies";
|
||||
|
||||
AppDomain curDom = AppDomain.CurrentDomain;
|
||||
builder = curDom.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
|
||||
|
||||
String proxyDll =
|
||||
System.Environment.GetEnvironmentVariable("XPCOM_DOTNET_SAVE_PROXIES");
|
||||
if (proxyDll != null) {
|
||||
module = builder.DefineDynamicModule(an.Name, proxyDll);
|
||||
} else {
|
||||
module = builder.DefineDynamicModule(an.Name);
|
||||
}
|
||||
|
||||
baseProxyCtor = typeof(BaseProxy).
|
||||
GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
|
||||
null, new Type[1] { typeof(IntPtr) }, null);
|
||||
guidCtor = typeof(System.Guid).
|
||||
GetConstructor(new Type[1] {typeof(string)});
|
||||
}
|
||||
|
||||
TypeBuilder tb;
|
||||
FieldInfo thisField;
|
||||
LocalBuilder bufLocal;
|
||||
ILGenerator ilg;
|
||||
|
||||
String proxyName;
|
||||
|
||||
internal ProxyGenerator(String name)
|
||||
{
|
||||
proxyName = name;
|
||||
}
|
||||
|
||||
internal Assembly Generate()
|
||||
{
|
||||
if (module.GetType(proxyName) != null)
|
||||
return module.Assembly;
|
||||
|
||||
String baseIfaceName = proxyName.Replace("Mozilla.XPCOM.Proxies.", "");
|
||||
String ifaceName = "Mozilla.XPCOM.Interfaces." + baseIfaceName;
|
||||
|
||||
Type ifaceType = System.Type.GetType(ifaceName +
|
||||
",Mozilla.XPCOM.Interfaces", true);
|
||||
|
||||
ushort inheritedMethodCount;
|
||||
String parentName = TypeInfo.GetParentInfo(baseIfaceName,
|
||||
out inheritedMethodCount);
|
||||
|
||||
Type parentType;
|
||||
if (parentName == null) {
|
||||
parentType = typeof(BaseProxy);
|
||||
} else {
|
||||
parentType = System.Type.GetType("Mozilla.XPCOM.Proxies." +
|
||||
parentName +
|
||||
",Mozilla.XPCOM.Proxies");
|
||||
}
|
||||
|
||||
Console.WriteLine("Defining {0} (inherits {1}, impls {2})",
|
||||
proxyName, parentType, ifaceName);
|
||||
tb = module.DefineType(proxyName, TypeAttributes.Class, parentType,
|
||||
new Type[1] { ifaceType });
|
||||
|
||||
thisField = typeof(BaseProxy).GetField("thisptr",
|
||||
BindingFlags.NonPublic |
|
||||
BindingFlags.Instance);
|
||||
|
||||
EmitProxyConstructor();
|
||||
|
||||
MethodDescriptor[] descs = TypeInfo.GetMethodData(baseIfaceName);
|
||||
|
||||
for (int i = inheritedMethodCount; i < descs.Length; i++) {
|
||||
if (descs[i] != null)
|
||||
GenerateProxyMethod(descs[i]);
|
||||
}
|
||||
|
||||
tb.CreateType();
|
||||
|
||||
thisField = null;
|
||||
tb = null;
|
||||
|
||||
return module.Assembly;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
#include <nsXPCOM.h>
|
||||
#include <nsDebug.h>
|
||||
#include <nsIInterfaceInfoManager.h>
|
||||
#include <nsCOMPtr.h>
|
||||
#include <xptinfo.h>
|
||||
#include <stdio.h>
|
||||
#include <nsString.h>
|
||||
#include <nsCRT.h>
|
||||
|
||||
nsIInterfaceInfoManager* infomgr;
|
||||
|
||||
extern "C" nsIEnumerator *
|
||||
typeinfo_EnumerateInterfacesStart()
|
||||
{
|
||||
nsIEnumerator *e;
|
||||
if (NS_FAILED(infomgr->EnumerateInterfaces(&e)) || NS_FAILED(e->First()))
|
||||
return 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
extern "C" char *
|
||||
typeinfo_EnumerateInterfacesNext(nsIEnumerator *e)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isup;
|
||||
while (1) {
|
||||
if (e->IsDone() != NS_ENUMERATOR_FALSE ||
|
||||
NS_FAILED(e->CurrentItem(getter_AddRefs(isup))) || !isup) {
|
||||
break;
|
||||
}
|
||||
|
||||
e->Next();
|
||||
nsCOMPtr<nsIInterfaceInfo> iface(do_QueryInterface(isup));
|
||||
if (!iface)
|
||||
break;
|
||||
|
||||
PRBool scriptable;
|
||||
if (NS_SUCCEEDED(iface->IsScriptable(&scriptable)) &&
|
||||
!scriptable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *name;
|
||||
iface->GetName(&name);
|
||||
return name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
typeinfo_EnumerateInterfacesStop(nsIEnumerator *e)
|
||||
{
|
||||
NS_IF_RELEASE(e);
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
typeinfo_GetParentInfo(const char *ifaceName,
|
||||
char **parentName,
|
||||
PRUint16 *parentMethodCount)
|
||||
{
|
||||
nsIInterfaceInfo *iinfo;
|
||||
nsresult res;
|
||||
|
||||
res = infomgr->GetInfoForName(ifaceName, &iinfo);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
nsCOMPtr<nsIInterfaceInfo> parent;
|
||||
res = iinfo->GetParent(getter_AddRefs(parent));
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
if (!parent) {
|
||||
*parentName = 0;
|
||||
*parentMethodCount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
res = parent->GetName(parentName);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
res = parent->GetMethodCount(parentMethodCount);
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
typeinfo_GetAllMethodData(const char *ifaceName,
|
||||
const nsXPTMethodInfo ***infos,
|
||||
PRUint16 *methodCount)
|
||||
{
|
||||
nsIInterfaceInfo *iinfo;
|
||||
nsresult res;
|
||||
|
||||
res = infomgr->GetInfoForName(ifaceName, &iinfo);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
res = iinfo->GetMethodCount(methodCount);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
const nsXPTMethodInfo **infoarr =
|
||||
new const nsXPTMethodInfo*[*methodCount];
|
||||
|
||||
*infos = &infoarr[0];
|
||||
|
||||
for (int i = 0; i < *methodCount; i++) {
|
||||
res = iinfo->GetMethodInfo(i, &infoarr[i]);
|
||||
if (NS_FAILED(res)) {
|
||||
fprintf(stderr, "Getting method info for %s:%d: %08x\n",
|
||||
ifaceName, i, res);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
typeinfo_GetMethodData(const char *ifaceName, int methIndex,
|
||||
const nsXPTMethodInfo **info)
|
||||
{
|
||||
nsIInterfaceInfo *iinfo;
|
||||
nsresult res;
|
||||
*info = 0;
|
||||
|
||||
res = infomgr->GetInfoForName(ifaceName, &iinfo);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
return iinfo->GetMethodInfo(methIndex, info);
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
typeinfo_GetMethodData_iid_index(const nsID *iid, int index,
|
||||
const nsXPTMethodInfo **info)
|
||||
{
|
||||
nsIInterfaceInfo *iinfo;
|
||||
nsresult res;
|
||||
*info = 0;
|
||||
|
||||
res = infomgr->GetInfoForIID(iid, &iinfo);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
return iinfo->GetMethodInfo(index, info);
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
typeinfo_GetMethodData_byname(const char *ifaceName, const char *methName,
|
||||
PRUint16 *index, const nsXPTMethodInfo **info)
|
||||
{
|
||||
nsIInterfaceInfo *iinfo;
|
||||
nsresult res;
|
||||
*info = 0;
|
||||
|
||||
res = infomgr->GetInfoForName(ifaceName, &iinfo);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
return iinfo->GetMethodInfoForName(methName, index, info);
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
typeinfo_GetIIDForParam(const char *ifaceName, int methIndex,
|
||||
int param, nsID *iid)
|
||||
{
|
||||
nsIInterfaceInfo *iinfo;
|
||||
nsresult res;
|
||||
|
||||
// fprintf(stderr, "getting IID for %s:%d:%d\n", ifaceName, methIndex,
|
||||
// param);
|
||||
|
||||
res = infomgr->GetInfoForName(ifaceName, &iinfo);
|
||||
if (NS_FAILED(res)) {
|
||||
fprintf(stderr, "%d: FAILED (%08x)\n", __LINE__, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
const nsXPTMethodInfo *meth;
|
||||
res = iinfo->GetMethodInfo(methIndex, &meth);
|
||||
if (NS_FAILED(res)) {
|
||||
fprintf(stderr, "%d: FAILED (%08x)\n", __LINE__, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
const nsXPTParamInfo& paramInfo = meth->GetParam(param);
|
||||
res = iinfo->GetIIDForParamNoAlloc(methIndex, ¶mInfo, iid);
|
||||
|
||||
char *idstr = iid->ToString();
|
||||
// fprintf(stderr, "outgoing iid is %s\n", idstr);
|
||||
nsCRT::free(idstr);
|
||||
if (NS_FAILED(res)) {
|
||||
fprintf(stderr, "%d: FAILED (%08x)\n", __LINE__, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
typeinfo_GetNameForIID(nsID *iid, char **ifaceName)
|
||||
{
|
||||
*ifaceName = 0;
|
||||
return infomgr->GetNameForIID(iid, ifaceName);
|
||||
}
|
||||
|
||||
extern "C" nsAString *
|
||||
typeinfo_WrapUnicode(const PRUnichar *chars, PRUint32 length)
|
||||
{
|
||||
return new nsString(chars, length);
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
typeinfo_FreeWrappedUnicode(nsAString *str)
|
||||
{
|
||||
delete str;
|
||||
}
|
|
@ -0,0 +1,530 @@
|
|||
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 implicit operator XPTType(TypeInfo.TypeDescriptor td)
|
||||
{
|
||||
XPTType t = new XPTType();
|
||||
t.prefix = (byte)(td.flags | 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 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
|
|
@ -0,0 +1,51 @@
|
|||
#include <nsIInterfaceInfoManager.h>
|
||||
#include <xptcall.h>
|
||||
#include <xpt_xdr.h>
|
||||
#include <nsCRT.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class WrappedCLR : public nsXPTCStubBase
|
||||
{
|
||||
public:
|
||||
typedef int (*MethodInvoker)(int, nsXPTCMiniVariant *);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo **aInfo);
|
||||
NS_IMETHOD CallMethod(PRUint16 methodIndex,
|
||||
const nsXPTMethodInfo *info,
|
||||
nsXPTCMiniVariant *params);
|
||||
WrappedCLR(MethodInvoker del, const nsIID &id) :
|
||||
mIID(id), mDelegate(del) { }
|
||||
virtual ~WrappedCLR() { }
|
||||
private:
|
||||
nsIID mIID;
|
||||
MethodInvoker mDelegate;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(WrappedCLR, nsISupports);
|
||||
|
||||
NS_IMETHODIMP
|
||||
WrappedCLR::GetInterfaceInfo(nsIInterfaceInfo **info)
|
||||
{
|
||||
extern nsIInterfaceInfoManager *infomgr;
|
||||
return infomgr->GetInfoForIID(&mIID, info);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WrappedCLR::CallMethod(PRUint16 methodIndex,
|
||||
const nsXPTMethodInfo *info,
|
||||
nsXPTCMiniVariant *params)
|
||||
{
|
||||
fprintf(stderr, "Calling %s via %p\n", info->GetName(), mDelegate);
|
||||
return mDelegate(methodIndex, params);
|
||||
}
|
||||
|
||||
extern "C" WrappedCLR *
|
||||
WrapCLRObject(WrappedCLR::MethodInvoker del, const nsIID &id)
|
||||
{
|
||||
char *idstr = id.ToString();
|
||||
fprintf(stderr, "Wrapping %p as %s\n", del, idstr);
|
||||
nsCRT::free(idstr);
|
||||
return new WrappedCLR(del, id);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Mozilla.XPCOM;
|
||||
|
||||
using MethodDescriptor = Mozilla.XPCOM.TypeInfo.MethodDescriptor;
|
||||
using ParamDescriptor = Mozilla.XPCOM.TypeInfo.ParamDescriptor;
|
||||
using ParamFlags = Mozilla.XPCOM.TypeInfo.ParamFlags;
|
||||
using TypeDescriptor = Mozilla.XPCOM.TypeInfo.TypeDescriptor;
|
||||
using TypeFlags = Mozilla.XPCOM.TypeInfo.TypeFlags;
|
||||
using TypeTag = Mozilla.XPCOM.TypeInfo.TypeTag;
|
||||
|
||||
namespace Mozilla.XPCOM {
|
||||
internal class CLRWrapper
|
||||
{
|
||||
public static IntPtr Wrap(object o, ref Guid iid)
|
||||
{
|
||||
CLRWrapper wrapper = new CLRWrapper(o, ref iid);
|
||||
return wrapper.MakeXPCOMProxy();
|
||||
}
|
||||
|
||||
int InvokeMethod(int index, IntPtr args)
|
||||
{
|
||||
Console.WriteLine("invoking method {0} on {1}", index,
|
||||
wrappedObj);
|
||||
MethodDescriptor desc = TypeInfo.GetMethodData(wrappedAsIID, index);
|
||||
Type ifaceType = TypeInfo.TypeForIID(wrappedAsIID);
|
||||
// Console.WriteLine("ifaceType: {0}", ifaceType);
|
||||
MethodInfo meth = ifaceType.GetMethod(desc.name);
|
||||
// Console.WriteLine("meth: {0}", meth);
|
||||
// This might just throw on you, if it's not a void-taking method
|
||||
meth.Invoke(wrappedObj, new object[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CLRWrapper(object o, ref Guid iid)
|
||||
{
|
||||
wrappedObj = o;
|
||||
wrappedAsIID = iid;
|
||||
}
|
||||
|
||||
object wrappedObj;
|
||||
Guid wrappedAsIID;
|
||||
|
||||
delegate int MethodInvoker(int index, IntPtr args);
|
||||
|
||||
[DllImport("xpcom-dotnet.so")]
|
||||
static extern IntPtr WrapCLRObject(MethodInvoker del, ref Guid iid);
|
||||
|
||||
IntPtr MakeXPCOMProxy()
|
||||
{
|
||||
return WrapCLRObject(new MethodInvoker(this.InvokeMethod),
|
||||
ref wrappedAsIID);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Mozilla.XPCOM
|
|
@ -0,0 +1,16 @@
|
|||
#include <nsXPCOM.h>
|
||||
#include <nsDebug.h>
|
||||
#include <nsIInterfaceInfoManager.h>
|
||||
#include <xptinfo.h>
|
||||
#include <nsCOMPtr.h>
|
||||
|
||||
extern "C" int
|
||||
StartXPCOM(nsIServiceManager** srvmgr)
|
||||
{
|
||||
nsresult res = NS_InitXPCOM2(srvmgr, 0, 0);
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
extern nsIInterfaceInfoManager *infomgr;
|
||||
infomgr = XPTI_GetInterfaceInfoManager();
|
||||
}
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Mozilla.XPCOM;
|
||||
using System.Globalization;
|
||||
|
||||
using MethodDescriptor = Mozilla.XPCOM.TypeInfo.MethodDescriptor;
|
||||
using ParamDescriptor = Mozilla.XPCOM.TypeInfo.ParamDescriptor;
|
||||
using ParamFlags = Mozilla.XPCOM.TypeInfo.ParamFlags;
|
||||
using TypeDescriptor = Mozilla.XPCOM.TypeInfo.TypeDescriptor;
|
||||
using TypeFlags = Mozilla.XPCOM.TypeInfo.TypeFlags;
|
||||
using TypeTag = Mozilla.XPCOM.TypeInfo.TypeTag;
|
||||
|
||||
namespace Mozilla.XPCOM {
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
struct XPTCMiniVariant
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public sbyte i8;
|
||||
[FieldOffset(0)]
|
||||
public Int16 i16;
|
||||
[FieldOffset(0)]
|
||||
public Int32 i32;
|
||||
[FieldOffset(0)]
|
||||
public Int64 i64;
|
||||
[FieldOffset(0)]
|
||||
public byte u8;
|
||||
[FieldOffset(0)]
|
||||
public UInt16 u16;
|
||||
[FieldOffset(0)]
|
||||
public UInt32 u32;
|
||||
[FieldOffset(0)]
|
||||
public UInt64 u64;
|
||||
[FieldOffset(0)]
|
||||
public float f;
|
||||
[FieldOffset(0)]
|
||||
public double d;
|
||||
[FieldOffset(0)]
|
||||
public Int32 b; /* PRBool */
|
||||
[FieldOffset(0)]
|
||||
public byte c;
|
||||
[FieldOffset(0)]
|
||||
public char wc;
|
||||
[FieldOffset(0)]
|
||||
public IntPtr p;
|
||||
[FieldOffset(0),MarshalAs(UnmanagedType.LPStr)]
|
||||
public string str;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
struct XPTCVariant
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public XPTCMiniVariant val;
|
||||
|
||||
[FieldOffset(8)]
|
||||
public IntPtr ptr;
|
||||
|
||||
[FieldOffset(12)] /* XXX assumes 4-byte IntPtr! */
|
||||
public XPTType type;
|
||||
|
||||
[FieldOffset(13)]
|
||||
public sbyte flags;
|
||||
}
|
||||
|
||||
public class Invoker
|
||||
{
|
||||
static void MarshalOneArg(ParamDescriptor param, object arg,
|
||||
IntPtr buffer)
|
||||
{
|
||||
string msg;
|
||||
if (param.flags != TypeInfo.ParamFlags.In) {
|
||||
msg = String.Format("{0} is {1} (only In " +
|
||||
"supported)", param.Name(),
|
||||
param.flags.ToString());
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
TypeInfo.TypeDescriptor type = param.type;
|
||||
|
||||
if ((type.flags & TypeFlags.Reference) != 0) {
|
||||
if ((type.flags & TypeFlags.Pointer) == 0) {
|
||||
throw new Exception("TD is Reference but " +
|
||||
"not Pointer?! (" +
|
||||
param.ToString() + ")");
|
||||
}
|
||||
|
||||
if (arg == null) {
|
||||
throw new Exception(param.Name() +
|
||||
": null passed as arg for " +
|
||||
"Reference param");
|
||||
}
|
||||
}
|
||||
|
||||
if (type.IsScalar()) {
|
||||
|
||||
XPTCVariant variant = new XPTCVariant();
|
||||
variant.type = type;
|
||||
variant.flags = 0;
|
||||
variant.ptr = IntPtr.Zero;
|
||||
Marshal.StructureToPtr(variant, buffer, false);
|
||||
|
||||
IntPtr p;
|
||||
switch (type.tag) {
|
||||
|
||||
case TypeTag.Int8:
|
||||
case TypeTag.Int16:
|
||||
case TypeTag.Int32:
|
||||
case TypeTag.UInt8:
|
||||
case TypeTag.UInt16:
|
||||
case TypeTag.UInt32:
|
||||
case TypeTag.Char:
|
||||
case TypeTag.WChar:
|
||||
Marshal.WriteInt32(buffer, (Int32)arg);
|
||||
break;
|
||||
|
||||
case TypeTag.UInt64:
|
||||
case TypeTag.Int64:
|
||||
Marshal.WriteInt64(buffer, (Int64)arg);
|
||||
break;
|
||||
|
||||
case TypeTag.Bool:
|
||||
bool b = (bool)arg;
|
||||
Marshal.WriteInt32(buffer, b ? 1 : 0);
|
||||
break;
|
||||
|
||||
case TypeTag.Float:
|
||||
float[] f = new float[] { (float)arg };
|
||||
Marshal.Copy(f, 0, buffer, 1);
|
||||
break;
|
||||
case TypeTag.Double:
|
||||
double[] d = new double[] { (double)arg };
|
||||
Marshal.Copy(d, 0, buffer, 1);
|
||||
break;
|
||||
|
||||
case TypeTag.String:
|
||||
Marshal.WriteIntPtr(buffer,
|
||||
Marshal.StringToCoTaskMemAnsi((string)arg));
|
||||
break;
|
||||
case TypeTag.WString:
|
||||
Marshal.WriteIntPtr(buffer,
|
||||
Marshal.StringToCoTaskMemUni((string)arg));
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = String.Format("{0}: type {1} not supported",
|
||||
param.Name(), type.tag.ToString());
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
Console.WriteLine("{0} @ {1:X2}", param.Name(),
|
||||
buffer.ToInt32());
|
||||
return;
|
||||
}
|
||||
|
||||
if (type.tag == TypeTag.Interface) {
|
||||
Guid iid = param.GetIID();
|
||||
Console.WriteLine("{0} is interface {1}",
|
||||
param.Name(), iid);
|
||||
Marshal.WriteIntPtr(buffer, CLRWrapper.Wrap(arg, ref iid));
|
||||
Console.WriteLine("{0} @ {1:X2}", param.Name(),
|
||||
buffer.ToInt32());
|
||||
return;
|
||||
}
|
||||
|
||||
msg = String.Format("{0} type {1} not yet supported ",
|
||||
param.Name(), type.tag.ToString());
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
[DllImport("xpcom-dotnet.so")]
|
||||
public static extern IntPtr WrapCLRObject(IntPtr obj, Guid id);
|
||||
|
||||
[DllImport("xpcom-dotnet.so")]
|
||||
static extern IntPtr typeinfo_WrapUnicode(IntPtr str,
|
||||
UInt32 length);
|
||||
|
||||
[DllImport("xpcom-dotnet.so")]
|
||||
static extern void typeinfo_FreeWrappedUnicode(IntPtr str);
|
||||
|
||||
static IntPtr MarshalArgs(MethodDescriptor desc, object[] args)
|
||||
{
|
||||
if (args.Length != desc.args.Length) {
|
||||
string msg = String.Format("{0} needs {1} args, {2} passed",
|
||||
desc.name, desc.args.Length,
|
||||
args.Length);
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
int variantsz = 16; /* sizeof(nsXPTCVariant) */
|
||||
int size = variantsz * args.Length;
|
||||
IntPtr argbuf = Marshal.AllocCoTaskMem(size);
|
||||
|
||||
for (int i = 0; i < args.Length; i++) {
|
||||
ParamDescriptor param = desc.args[i];
|
||||
IntPtr current = (IntPtr)(argbuf.ToInt32() + variantsz * i);
|
||||
object arg = args[i];
|
||||
|
||||
MarshalOneArg(param, arg, current);
|
||||
}
|
||||
|
||||
return argbuf;
|
||||
}
|
||||
|
||||
static void FreeOneMarshalledArg(ParamDescriptor param, IntPtr buffer)
|
||||
{
|
||||
}
|
||||
|
||||
static void DemarshalArgs(MethodDescriptor desc,
|
||||
IntPtr argbuf)
|
||||
{
|
||||
int variantsz = Marshal.SizeOf(typeof(XPTCVariant));
|
||||
for (int i = 0; i < desc.args.Length; i++) {
|
||||
ParamDescriptor param = desc.args[i];
|
||||
IntPtr current = (IntPtr)(argbuf.ToInt32() + variantsz * i);
|
||||
FreeOneMarshalledArg(param, current);
|
||||
}
|
||||
Marshal.FreeCoTaskMem(argbuf);
|
||||
}
|
||||
|
||||
public static int XPTC_InvokeByIndexSafe(IntPtr that, Int32 index,
|
||||
UInt32 argCount, IntPtr args)
|
||||
{
|
||||
Console.WriteLine("XPTC_IBI: {0:X2}:{1}({2}:{3:X2})",
|
||||
that.ToInt32(), index, argCount, args.ToInt32());
|
||||
return XPTC_InvokeByIndex(that, index, argCount, args);
|
||||
}
|
||||
|
||||
[DllImport("libxpcom.so")]
|
||||
static extern int XPTC_InvokeByIndex(IntPtr that, Int32 methodIndex,
|
||||
UInt32 argCount,
|
||||
IntPtr args);
|
||||
|
||||
public static object Invoke(IntPtr that, string iface,
|
||||
string method, params object[] args)
|
||||
{
|
||||
return Invoke(that, TypeInfo.GetMethodData(iface, method), args);
|
||||
}
|
||||
|
||||
public static object Invoke(IntPtr that, string iface,
|
||||
int method, params object[] args)
|
||||
{
|
||||
return Invoke(that, TypeInfo.GetMethodData(iface, method), args);
|
||||
}
|
||||
|
||||
public static object Invoke(IntPtr that, MethodDescriptor desc,
|
||||
params object[] args)
|
||||
{
|
||||
IntPtr argbuf = MarshalArgs(desc, args);
|
||||
int res = XPTC_InvokeByIndex(that, desc.index,
|
||||
(UInt32)args.Length, argbuf);
|
||||
DemarshalArgs(desc, argbuf);
|
||||
if (res != 0) {
|
||||
throw new Exception(String.Format("XPCOM Error: {0:X2}",
|
||||
res));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Mozilla.XPCOM
|
|
@ -0,0 +1,168 @@
|
|||
using System;
|
||||
using Mozilla.XPCOM;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Collections;
|
||||
|
||||
public class Generate
|
||||
{
|
||||
ModuleBuilder mb;
|
||||
Hashtable ifaceTable = new Hashtable();
|
||||
bool verbose = false;
|
||||
PropertyBuilder lastProperty = null;
|
||||
const PropertyAttributes PROPERTY_ATTRS = PropertyAttributes.None;
|
||||
const MethodAttributes METHOD_ATTRS = MethodAttributes.Public |
|
||||
MethodAttributes.Abstract | MethodAttributes.Virtual;
|
||||
|
||||
Type FixupInterfaceType(TypeInfo.ParamDescriptor desc)
|
||||
{
|
||||
try {
|
||||
String ifaceName = desc.GetInterfaceName();
|
||||
return EmitOneInterface(ifaceName);
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine(e);
|
||||
return typeof(object);
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateInterfaceMethod(TypeBuilder tb,
|
||||
TypeInfo.MethodDescriptor desc)
|
||||
{
|
||||
if (desc == null || !desc.IsVisible())
|
||||
return;
|
||||
|
||||
MethodAttributes methodAttrs = METHOD_ATTRS;
|
||||
|
||||
String methodName = desc.name;
|
||||
if (desc.IsGetter()) {
|
||||
methodName = "get_" + desc.name;
|
||||
methodAttrs |= MethodAttributes.SpecialName;
|
||||
} else if (desc.IsSetter()) {
|
||||
methodName = "set_" + desc.name;
|
||||
methodAttrs |= MethodAttributes.SpecialName;
|
||||
}
|
||||
|
||||
// Fix up interface types in parameters
|
||||
Type ret = desc.resultType;
|
||||
if (ret == typeof(object))
|
||||
ret = FixupInterfaceType(desc.args[desc.args.Length - 1]);
|
||||
Type[] argTypes = (Type[])desc.argTypes.Clone();
|
||||
for (int i = 0; i < argTypes.Length; i++) {
|
||||
if (argTypes[i] == typeof(object))
|
||||
argTypes[i] = FixupInterfaceType(desc.args[i]);
|
||||
}
|
||||
MethodBuilder meth = tb.DefineMethod(methodName, methodAttrs, ret,
|
||||
argTypes);
|
||||
|
||||
if (desc.IsSetter()) {
|
||||
if (lastProperty != null && lastProperty.Name == desc.name) {
|
||||
lastProperty.SetSetMethod(meth);
|
||||
} else {
|
||||
tb.DefineProperty(desc.name, PROPERTY_ATTRS, ret, new Type[0])
|
||||
.SetSetMethod(meth);
|
||||
}
|
||||
lastProperty = null;
|
||||
} else if (desc.IsGetter()) {
|
||||
lastProperty = tb.DefineProperty(desc.name, PROPERTY_ATTRS, ret,
|
||||
new Type[0]);
|
||||
lastProperty.SetGetMethod(meth);
|
||||
} else {
|
||||
lastProperty = null;
|
||||
}
|
||||
}
|
||||
|
||||
Type EmitOneInterface(String name)
|
||||
{
|
||||
if (ifaceTable.ContainsKey(name))
|
||||
return (Type)ifaceTable[name];
|
||||
Console.WriteLine("Interface: {0}", name);
|
||||
|
||||
ushort inheritedMethodCount;
|
||||
String parentName = TypeInfo.GetParentInfo(name,
|
||||
out inheritedMethodCount);
|
||||
Type parentType;
|
||||
|
||||
if (parentName == null)
|
||||
parentType = typeof(object);
|
||||
else
|
||||
parentType = EmitOneInterface(parentName);
|
||||
|
||||
TypeBuilder ifaceTb = mb.DefineType("Mozilla.XPCOM.Interfaces." + name,
|
||||
TypeAttributes.Public |
|
||||
TypeAttributes.Interface,
|
||||
parentType);
|
||||
ifaceTable.Add(name, ifaceTb);
|
||||
|
||||
TypeInfo.MethodDescriptor[] descs;
|
||||
try {
|
||||
descs = TypeInfo.GetMethodData(name);
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine("skipping interface {0}: {1}", name,
|
||||
ex.Message);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (descs == null) {
|
||||
Console.WriteLine("No descs!");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
Console.WriteLine("{0} has {1} methods ({2} inherited from {3})",
|
||||
name, descs.Length, inheritedMethodCount,
|
||||
parentName);
|
||||
}
|
||||
for (int i = inheritedMethodCount; i < descs.Length; i++) {
|
||||
GenerateInterfaceMethod(ifaceTb, descs[i]);
|
||||
}
|
||||
|
||||
ifaceTb.CreateType();
|
||||
return ifaceTb;
|
||||
}
|
||||
|
||||
void GenerateInterfaceAssembly(string[] args)
|
||||
{
|
||||
String dllName = args[0];
|
||||
String onlyInterface = null;
|
||||
if (args.Length > 1)
|
||||
onlyInterface = args[1];
|
||||
AssemblyName an = new AssemblyName();
|
||||
an.Version = new Version(1, 0, 0, 0);
|
||||
an.Name = "Mozilla.XPCOM.Interfaces";
|
||||
|
||||
AssemblyBuilder ab = AppDomain.CurrentDomain.
|
||||
DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
|
||||
mb = ab.DefineDynamicModule(an.Name, dllName);
|
||||
|
||||
if (onlyInterface != null) {
|
||||
verbose = true;
|
||||
EmitOneInterface(onlyInterface);
|
||||
} else {
|
||||
IntPtr e = TypeInfo.typeinfo_EnumerateInterfacesStart();
|
||||
if (e == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
while (true) {
|
||||
String name = TypeInfo.typeinfo_EnumerateInterfacesNext(e);
|
||||
if (name == null)
|
||||
break;
|
||||
EmitOneInterface(name);
|
||||
}
|
||||
|
||||
TypeInfo.typeinfo_EnumerateInterfacesStop(e);
|
||||
}
|
||||
|
||||
ab.Save(dllName);
|
||||
|
||||
Console.WriteLine("Generated metadata for {0} interfaces in {1}",
|
||||
ifaceTable.Count, dllName);
|
||||
}
|
||||
|
||||
public static void Main(String[] args)
|
||||
{
|
||||
Components.Init();
|
||||
|
||||
Generate gen = new Generate();
|
||||
gen.GenerateInterfaceAssembly(args);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче