C#COM和附加事件

时间:2014-07-17 17:56:00

标签: c# events com

所以,我有这个传统类型的应用程序,我试图理解和维护,需要一些帮助。 我没有涉及远程处理,但这个解决方案似乎是使用第三方COM组件。

文档是合理的,但没有谈论.NET以及如何附加事件处理程序。相反,它通过Activator.CreateInstance文档(并在解决方案中使用)有关如何创建对象实例。

目前正在这样做:

mainObj = Activator.CreateInstance(Type.GetTypeFromProgID("xxxRemote.clsxxxJob"));

没关系。

但是我想附加一个事件处理程序来监听Activator创建的实例化对象上的特定事件。

文档向我展示了暴露的事件,但没有关于如何在使用此方法时进行连接的示例。

任何人都有关于如何在使用COM时连接事件的想法吗?

1 个答案:

答案 0 :(得分:1)

应该通过正常反思。

msdn中有一个指南,如http://msdn.microsoft.com/en-us/library/ms228976(v=vs.110).aspx

问题是,要定义将挂钩到事件的方法,您将不会定义类型,并且必须执行一些IL发出黑魔法来在运行时构建方法。这是一个有趣的问题。

我正在发送一个通过COM打开ADO连接的“正常”方式的例子(只是为了有一些会调用事件处理程序)。然后,我有另一个做这个的例子,艰难的方式。

对于代码中的混乱感到抱歉,但它只是一个示例。

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;
using ADODB;
using System.Reflection.Emit;

namespace COMTests.Tests
{
[TestClass]
public class UnitTest1
{
    private string server;
    private string database;
    private string user;
    private string password;                

    [TestInitialize]
    public void Initialize()
    {
        this.server = "";
        this.database = "";
        this.user = "";
        this.password = "";
    }

    [TestMethod]
    public void TestCreateConectionTheSaneWay()
    {
        ADODB.Connection connection = new ADODB.Connection();
        connection.Provider = "sqloledb";
        connection.ConnectionString = String.Format("Server={0};Database={1};User Id={2};Password={3}",
            this.server, this.database, this.user, this.password);
        connection.ConnectComplete += new ADODB.ConnectionEvents_ConnectCompleteEventHandler(TheConnectionComplete);
        connection.Open();


    }

    [TestMethod]
    public void TestCreateConnectionTheInsaneWay()
    {            
        Type connectionType = Type.GetTypeFromProgID("ADODB.Connection");

        EventInfo eventType = connectionType.GetEvent("ConnectComplete");            

        Type[] argumentTypes =
            (from ParameterInfo p in eventType.EventHandlerType.GetMethod("Invoke").GetParameters()
             select p.ParameterType).ToArray<Type>();

        MethodInfo handler = FabricateAMethod(argumentTypes, "Wow! Should I be happy because it works?", 
            "Ass2", "Type2", "Method2");            
        Delegate d2 = Delegate.CreateDelegate(eventType.EventHandlerType, handler, true);                       

        object o = Activator.CreateInstance(connectionType);
        eventType.AddEventHandler(o, d2);            

        connectionType.GetProperty("Provider").SetValue(o, "sqloledb", null);
        connectionType.GetProperty("ConnectionString").SetValue(o, String.Format("Server={0};Database={1};User Id={2};Password={3}",
            this.server, this.database, this.user, this.password), null);
        connectionType.GetMethod("Open").Invoke(o, new object[] { "", "", "", -1 });            

    }

    [TestMethod]
    public void TestFabricatedMethod()
    {    
        MethodInfo m = FabricateAMethod(new Type[] {}, "Yeap. Works.", "Ass1", "Type1", "Method1");
        m.Invoke(null, new Object[] { });
    }

    private MethodInfo FabricateAMethod(Type[] arguments, string stringToPrint, string assemblyName, 
        string typeName, string methodName)
    {
        AssemblyName aName = new AssemblyName(assemblyName);
        AssemblyBuilder ab =
            AppDomain.CurrentDomain.DefineDynamicAssembly(
                aName,
                AssemblyBuilderAccess.RunAndSave);
        ModuleBuilder mb =
           ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

        TypeBuilder tb = mb.DefineType(
            typeName,
            TypeAttributes.Public);

        MethodBuilder method = tb.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static,
           typeof(void), arguments);

        MethodInfo writeString = typeof(Console).GetMethod("WriteLine",
        new Type[] { typeof(string) });
        ILGenerator il = method.GetILGenerator();

        il.Emit(OpCodes.Ldstr, stringToPrint);
        il.EmitCall(OpCodes.Call, writeString, null);
        il.Emit(OpCodes.Ret);

        return tb.CreateType().GetMethod(methodName);
    }

    public static void TheConnectionComplete(Error pError, ref EventStatusEnum adStatus, Connection pConnection)
    {
        Console.WriteLine("The normal way.");
    }

}

}