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:
shaver%mozilla.org 2005-02-01 23:58:57 +00:00
Родитель 4429a9bd0e
Коммит 47bcc65e52
11 изменённых файлов: 1944 добавлений и 0 удалений

Просмотреть файл

@ -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, &paramInfo, 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);
}
}