dotNET 为COM实例挂接事件

       一般来说COM类要想要具有事件通知,那么它必须实现事件源,但事件源具有两类形式一类是传统的“IConnectPoint”接口方式“点对点”挂接,比较麻烦需要知道被挂接事件接口的IID,另一类是“IReflect”接口挂接,它不需要知道挂接事件接口的IID。

      一般来说大多数COM事件的挂接,都只采取传统的方式用“IConnectPoint”挂接,而类似如“MSXML2.XMLHTTP”这类COM对象的事件就必须要用“IReflect”接口挂接。

      COM技术在现在的时代已经可以算过时了,还会用、提到的人越来越稀少(莫说别人,我自己也快忘得差不多了),不过上面的两个挂接方法的确是足够的经典,今天就写个demo,天秀一波,炒炒冷饭!

       经典的“事件挂接”,挂接成功后返回“事件挂接 cookie”

        public static int Advise(object obj, Guid riid, object sink)
        {
            int cookie = -1;
            IConnectionPointContainer icpc = obj as IConnectionPointContainer;
            if (icpc != null)
            {
                IConnectionPoint icp = null;
                try
                {
                    icpc.FindConnectionPoint(ref riid, out icp);
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.Message);
                }
                if (icp != null)
                {
                    icp.Advise(sink, out cookie);
                }
            }
            return cookie;
        }

       苍天啊,让我们秀一把啊,请你闭上眼睛,以免误伤!

        public static int AtlAdvise(object obj, Guid riid, object sink)
        {
            if (advise == null)
            {
                Type[] Types = { typeof(object), typeof(Guid), typeof(object) };
                advise = new DynamicMethod("Advise", typeof(int), Types, true);
                var mdil = advise.GetILGenerator();
                var lbTrue = mdil.DefineLabel();
                Types = new Type[] { typeof(int), typeof(IConnectionPoint), typeof(IConnectionPointContainer), typeof(Guid), typeof(Exception),
                    typeof(Debug), typeof(string) };

                mdil.DeclareLocal(Types[0]);
                mdil.DeclareLocal(Types[1]);
                mdil.DeclareLocal(Types[2]);

                mdil.Emit(OpCodes.Ldc_I4_M1);
                mdil.Emit(OpCodes.Stloc_0);

                mdil.Emit(OpCodes.Ldarg_S, 0);
                mdil.Emit(OpCodes.Isinst, Types[2]);
                mdil.Emit(OpCodes.Stloc_2);

                mdil.Emit(OpCodes.Ldloc_2);
                mdil.Emit(OpCodes.Ldnull);
                mdil.Emit(OpCodes.Ceq);
                mdil.Emit(OpCodes.Brtrue, lbTrue);

                mdil.BeginExceptionBlock();

                mdil.Emit(OpCodes.Ldloc_2);
                mdil.Emit(OpCodes.Ldarga, 1);
                mdil.Emit(OpCodes.Ldloca, 1);
                mdil.Emit(OpCodes.Callvirt, Types[2].GetMethod("FindConnectionPoint"));

                mdil.Emit(OpCodes.Ldloc_1);
                mdil.Emit(OpCodes.Ldarg_2);
                mdil.Emit(OpCodes.Ldloca, 0);
                mdil.Emit(OpCodes.Callvirt, Types[1].GetMethod("Advise"));

                mdil.BeginCatchBlock(Types[4]);

                mdil.Emit(OpCodes.Callvirt, Types[4].GetMethod("get_Message"));
                mdil.Emit(OpCodes.Call, Types[5].GetMethod("WriteLine", new Type[] { Types[6] }));

                mdil.EndExceptionBlock();
                mdil.MarkLabel(lbTrue);

                mdil.Emit(OpCodes.Ldloc_0);
                mdil.Emit(OpCodes.Ret);
            }
            return (int)advise.Invoke(advise, new object[] { obj, riid, sink });
        }

       经典的“取消事件挂接”,返回取消是否成功。

        public static bool Unadvise(object obj, Guid riid, object sink)
        {
            int cookie = -1;
            IConnectionPointContainer icpc = obj as IConnectionPointContainer;
            if (icpc != null)
            {
                IConnectionPoint icp = null;
                try
                {
                    icpc.FindConnectionPoint(ref riid, out icp);
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.Message);
                }
                try
                {
                    icp.Unadvise(cookie);
                    return true;
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.Message);
                }
            }
            return false;
        }

     喜迎陈独秀同学!

        public static bool AtlUnadvise(object obj, Guid riid, int cookie)
        {
            if (unadvise == null)
            {
                Type[] Types = { typeof(object), typeof(Guid), typeof(int) };
                unadvise = new DynamicMethod("Unadvise", typeof(bool), Types, true);
                Types = new Type[] { typeof(bool), typeof(IConnectionPoint),
                    typeof(IConnectionPointContainer), typeof(Exception), typeof(Debug), typeof(string), typeof(DWebBrowserEvents) };

                var il = unadvise.GetILGenerator();
                for (var i = 0; i < 3; i++)
                    il.DeclareLocal(Types[i]);
                var lbTrue = il.DefineLabel();

                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Stloc_0);

                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Isinst, Types[2]);
                il.Emit(OpCodes.Stloc_2);

                il.Emit(OpCodes.Ldloc_2);
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ceq);
                il.Emit(OpCodes.Brtrue, lbTrue);

                il.BeginExceptionBlock();

                il.Emit(OpCodes.Ldloc_2);
                il.Emit(OpCodes.Ldarga, 1);
                il.Emit(OpCodes.Ldloca, 1);
                il.Emit(OpCodes.Callvirt, Types[2].GetMethod("FindConnectionPoint"));

                il.Emit(OpCodes.Ldloc_1);
                il.Emit(OpCodes.Ldarg_2);
                il.Emit(OpCodes.Callvirt, Types[1].GetMethod("Unadvise"));

                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Stloc_0);

                il.BeginCatchBlock(Types[3]);

                il.Emit(OpCodes.Callvirt, Types[3].GetMethod("get_Message"));
                il.Emit(OpCodes.Call, Types[4].GetMethod("WriteLine", new Type[] { Types[5] }));

                il.EndExceptionBlock();
                il.MarkLabel(lbTrue);

                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Ret);
            }
            return (bool)AtlUnadvise(obj, riid, cookie);
        }

    上面秀了这么多,“IReflect”接口方式挂接呢?本文将以“MSXML2.XMLHTTP”为例子来一个demo来秀天地秀地板,展示我作为一个合格”菜鸟“的正确姿态。

namespace TECHMARS.VM
{
    using System;
    using System.Globalization;
    using System.Reflection;
    using System.Runtime.InteropServices;

    class Program
    {
        [MTAThread]
        static void Main(string[] args)
        {
            dynamic xhr = Activator.CreateInstance(Type.GetTypeFromProgID("MSXML2.XMLHTTP"));
            xhr.open(
                "GET",
                "http://zhangmenshiting.qianqian.com/data2/music/d94b2fcee28daff91d4ef0097ac868f9/556455954/556455954.mp3?xcode=8369c60cd042ff6e26d7084657a59bf4",
                true);
            xhr.onreadystatechange = new XhrToClrEventProxy((object)xhr, "onreadystatechange", (sender, e) =>
            {
                Console.WriteLine(xhr.readyState);
            });
            xhr.send(null);
            Console.ReadLine();
        }

        [Guid("F55597A2-D12E-4C2B-AF23-D877634796C7")]
        private class XhrToClrEventProxy : IReflect
        {
            private string evtName;
            private object sender;
            private IReflect reflect;
            private EventHandler evtHandler;

            public string EventName
            {
                get
                {
                    return this.evtName;
                }
            }

            Type IReflect.UnderlyingSystemType
            {
                get
                {
                    return this.reflect.UnderlyingSystemType;
                }
            }

            FieldInfo IReflect.GetField(string name, BindingFlags attr)
            {
                return this.reflect.GetField(name, attr);
            }

            FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr)
            {
                return this.reflect.GetFields(bindingAttr);
            }

            MemberInfo[] IReflect.GetMember(string name, BindingFlags attr)
            {
                return this.reflect.GetMember(name, attr);
            }

            MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr)
            {
                return this.reflect.GetMembers(bindingAttr);
            }

            MethodInfo IReflect.GetMethod(string name, BindingFlags attr)
            {
                return this.reflect.GetMethod(name, attr);
            }

            MethodInfo IReflect.GetMethod(string name, BindingFlags attr, Binder binder, Type[] types, ParameterModifier[] modifiers)
            {
                return this.reflect.GetMethod(name, attr, binder, types, modifiers);
            }

            MethodInfo[] IReflect.GetMethods(BindingFlags attr)
            {
                return this.reflect.GetMethods(attr);
            }

            PropertyInfo[] IReflect.GetProperties(BindingFlags attr)
            {
                return this.reflect.GetProperties(attr);
            }

            PropertyInfo IReflect.GetProperty(string name, BindingFlags attr)
            {
                return this.reflect.GetProperty(name, attr);
            }

            PropertyInfo IReflect.GetProperty(string name, BindingFlags attr, Binder binder, Type ret, Type[] types, ParameterModifier[] modifiers)
            {
                return this.reflect.GetProperty(name, attr, binder, ret, types, modifiers);
            }

            object IReflect.InvokeMember(string name, BindingFlags attr, Binder binder, object obj, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] nameds)
            {
                if (name == "[DISPID=0]")
                {
                    EventHandler handler = this.evtHandler;
                    if (handler != null)
                    {
                        handler(this.sender, EventArgs.Empty);
                    }
                    return null;
                }
                return this.reflect.InvokeMember(name, attr, binder, obj, args, modifiers, culture, nameds);
            }

            public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
            {
                throw new NotImplementedException();
            }

            public XhrToClrEventProxy(object sender, string evtName, EventHandler evtHandler)
            {
                if (evtName == null)
                {
                    throw new ArgumentNullException("evtName");
                }
                if (sender == null)
                {
                    throw new ArgumentNullException("sender");
                }
                if (evtHandler == null)
                {
                    throw new ArgumentNullException("eventHandler");
                }
                if (evtName.Length <= 0)
                {
                    throw new ArgumentException("evtName");
                }
                this.reflect = typeof(XhrToClrEventProxy);
                this.sender = sender;
                this.evtName = evtName;
                this.evtHandler = evtHandler;
            }
        }
    }
}

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页