c# COM和附加事件
本文关键字:事件 COM | 更新日期: 2023-09-27 18:13:19
所以,我有这个遗留类型的应用程序,我试图理解和维护,需要一些帮助。我没有涉足Remoting,但这个解决方案似乎是使用第三方COM组件。
文档是合理的,但没有谈论太多关于。net和如何附加事件处理程序。相反,它记录(并在解决方案中使用)如何通过Activator.CreateInstance创建对象的实例。
所以现在它是这样做的:
mainObj = Activator.CreateInstance(Type.GetTypeFromProgID("xxxRemote.clsxxxJob"));
没关系。
但是我想附加一个事件处理程序来监听Activator创建的实例化对象上的特定事件。
文档为我提供了公开的事件,但没有示例说明在使用这种方法时如何将它们连接起来。
有谁对如何在使用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.");
}
}
}