سؤال

I got an DLL registered on my local system. (Which I didn't own)

When I create the COM object using VBScript and calling the function everything works fine:

set Elo = CreateObject("jniwrapper.elocomserver")
Elo.refreshIntray()

But when using C#.net I get an NotImplementedException:

A NotImplementedException got thrown!

Type javaClientComServerType = Type.GetTypeFromProgID("jniwrapper.elocomserver");
dynamic eloJavaClient = Activator.CreateInstance(javaClientComServerType);

eloJavaClient.refreshIntray();

Any idea whats going on here and how to fix it?

هل كانت مفيدة؟

المحلول

This seems to be an issue related with .NET COM interop through DLR (dynamic language runtime) in association with the COM bridge that the COM-Server (Java program wrapped through JNI utilizes). I suspect the latter to be ComfyJ from Teamdev. You can work around the issue by providing an implementation of IDynamicMetaObjectProvider and DynamicMetaObject. For a start see the code below:

using System;
using System.Collections.Generic;
using System.Text;
using System.Dynamic;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Diagnostics;

class DynamicCOMObject : IDynamicMetaObjectProvider, IDisposable 
{
    private Type m_comType = null;
    private object m_comHolder = null;

    public DynamicCOMObject(string progId)
    {        
        m_comType = Type.GetTypeFromProgID(progId);
        m_comHolder = Activator.CreateInstance(m_comType);
    }

    public void Dispose()
    {
        if (m_comHolder != null)
        {
            Marshal.ReleaseComObject(m_comHolder);
            m_comHolder = null;
        }
    }

    #region IDynamicMetaObjectProvider Members
    DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(
        System.Linq.Expressions.Expression parameter)
    {
        return new DynamicCOMObjectMetaObject(parameter, this);
    }
    #endregion

    private class DynamicCOMObjectMetaObject : DynamicMetaObject
    {
        internal DynamicCOMObjectMetaObject(
            System.Linq.Expressions.Expression parameter,
            DynamicCOMObject value)
            : base(parameter, BindingRestrictions.Empty, value)
        {
        }

        public override DynamicMetaObject BindSetMember(SetMemberBinder binder,
            DynamicMetaObject value)
        {
            // Method to call in the containing class:
            string methodName = "SetValue";

            // setup the binding restrictions.
            BindingRestrictions restrictions =
                BindingRestrictions.GetTypeRestriction(Expression, LimitType);

            // setup the parameters:
            Expression[] args = new Expression[2];
            // First parameter is the name of the property to Set
            args[0] = Expression.Constant(binder.Name);
            // Second parameter is the value
            args[1] = Expression.Convert(value.Expression, typeof(object));

            // Setup the 'this' reference
            Expression self = Expression.Convert(Expression, LimitType);

            // Setup the method call expression
            Expression methodCall = Expression.Call(self,
                    typeof(DynamicCOMObject).GetMethod(methodName),
                    args);

            // Create a meta object to invoke Set later:
            DynamicMetaObject setDictionaryEntry = new DynamicMetaObject(
                methodCall,
                restrictions);
            // return that dynamic object
            return setDictionaryEntry;
        }

        public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
        {
            // Method call in the containing class:
            string methodName = "GetValue";

            // One parameter
            Expression[] parameters = new Expression[]
            {                
                Expression.Constant(binder.Name)
            };

            DynamicMetaObject getDictionaryEntry = new DynamicMetaObject(
                Expression.Call(
                    Expression.Convert(Expression, LimitType),
                    typeof(DynamicCOMObject).GetMethod(methodName),
                    parameters),
                BindingRestrictions.GetTypeRestriction(Expression, LimitType));
            return getDictionaryEntry;
        }

        public override DynamicMetaObject BindInvokeMember(
            InvokeMemberBinder binder, DynamicMetaObject[] args)
        {
            Expression[] parameters = new Expression[2];
            Expression[] subs = new Expression[args.Length];

            parameters[0] = Expression.Constant(binder.Name);

            for (int i = 0; i < args.Length; i++)
                subs[i] = args[i].Expression;

            parameters[1] = Expression.NewArrayInit(typeof(object), subs);

            DynamicMetaObject methodInfo = new DynamicMetaObject(
                Expression.Call(
                Expression.Convert(Expression, LimitType),
                typeof(DynamicCOMObject).GetMethod("CallMethod"),
                parameters),
                BindingRestrictions.GetTypeRestriction(Expression, LimitType));
            return methodInfo;
        }
    }

    public object SetValue(string key, object value)
    {
        return m_comType.InvokeMember(key,
            BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.Public,
            null,
            m_comHolder,
            new object[] { value });   
    }

    public object GetValue(string key)
    {
        return m_comType.InvokeMember(key,
            BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public,
            null,
            m_comHolder,
            null);          
    }

    public object CallMethod(string methodName, params object[] parameters)
    {
        return m_comType.InvokeMember(methodName,
            BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
            null,
            m_comHolder,
            parameters);        
    }
}

Usage:

        using (dynamic client = new DynamicCOMObject("jniwrapper.elocomserver"))
        {                
            client.refreshIntray();
        }

نصائح أخرى

Just for documentation; there's a short way:

class EloComServer : DynamicObject, IDisposable
{
    private Type javaClientType;
    private object elo;

    public EloComServer()
    {
        javaClientType = Type.GetTypeFromProgID("jniwrapper.elocomserver");
        elo = Activator.CreateInstance(javaClientType);
    }

    ~EloComServer()
    {
        this.Dispose();
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        try
        {
            result = javaClientType.InvokeMember(binder.Name,
                    BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
                    null, elo, args);

            return true;
        }
        catch
        {
            result = null;
            return false;
        }
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        try
        {
            javaClientType.InvokeMember(binder.Name,
                    BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance,
                    null, elo, new object[] { value });

            return true;
        }
        catch
        {
            return false;
        }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        try
        {
            result = javaClientType.InvokeMember(binder.Name,
                    BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance,
                    null, elo, new object[0]);

            return true;
        }
        catch
        {
            result = null;
            return false;
        }
    }

    #region IDisposable Members

    public void Dispose()
    {
        if (this.elo != null)
        {
            Marshal.ReleaseComObject(elo); 
        }
    }

    #endregion
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top