c# COM和附加事件

本文关键字:事件 COM | 更新日期: 2023-09-27 18:13:19

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

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

所以现在它是这样做的:

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

没关系。

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

文档为我提供了公开的事件,但没有示例说明在使用这种方法时如何将它们连接起来。

有谁对如何在使用COM时像这样连接事件有任何想法?

c# COM和附加事件

应该通过正常反射。

在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.");
    }
}

}