zoukankan      html  css  js  c++  java
  • 公共语言运行库(CLR)开发系列课程(3):COM Interop基础 学习笔记

    • 上章地址

    • 什么是COM

      • Component Object Model 组建对象模型  

      • 基于接口(Interface)

        • 接口=协议
        • IID 标识接口
        • V-table 虚表 方式调用
        • 单继承 
      • 对象(Object)

        • 实现一个或者多个接口
    • 举例:IDispatch接口

    • 为什么要使用COM Interop

      • 重用代码:使用.NET调用已有的COM组件,提高生产率:使用.NET编写COM组件 
    • COM Interop基础概念

      • RCW:Runtime Callable Wrapper  .NET可调用COM组件的包装代理   .NET=>RCW=>COM 
      • CCW:Com Callable Wrapper     COM可调用的包装代理            COM=>CCW=>.NET
    • RCW基础

      • 定义COM接口

        [ComImport]
        [Guid("....")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IMyInterface
        {
               void Func();
        }
      • Attributes

        • ComImport 接口按照对应的COM接口定义
        • Guid 指定IID
        • InterfaceType
          • ComInterfaceType.InterfaceIsIUnknown 在.NET调用COM组件的时候总是用虚表的方式调用 和C++调用虚函数一样 要知道函数指针以及偏移量 
            • Early Bound  早绑定
            • 基于虚表
            • 函数顺序必须和COM接口完全一致    但是如果你不用后面方法只调用前三个 那么只需要前三个方法对应就行了 不建议可能导致顺序婚论
          • ComInterfaceType.InterfaceIsIDispatch 通过函数名字 和 Displd调用   COM组件用VB写的建议使用这种方式调用 这种方式中间会有Invoke 会慢点 方便点
            • Late Bound  后期绑定
            • 支持IDispatch
            • 通过Displd 属性指定Dispatch ID 或者自动生成
            • 函数顺序不重要  
          • ComInterfaceType.InterfaceIsDual     既支持虚表调用也支持IDispatch方式调用   上面两种他都支持
            • 支持  IUnknown和IDispatch两种方式  他需要 顺序和ID都要对
    • 接口的继承      

      • 需要重新定义父接口的成员函数   父接口函数放前面  自身接口放后面 按顺序声明
        [ComImport]
        interface IA
        {
          void FuncA();
        }
        [ComImport]
        interface IB:IA
        {
            void new FuncA();
            void FuncB();   
        }
    • 定义RCW

      • [ComImport]
        public class MyRcw:IMyInterface
        {
              [MethodImplAttribute(MethodImplOptions.InternalCall)]
              public extern void MyFunc();
        }    
      • ComImport 告诉CLR这个是RCW

      • extern + InternalCall 函数由CLR内部实现 具有ComImport特性的时候必须使用extern和InternalCall 强制约束

    • 自动生成RCW:TlbImp

      • TlbImp<tlb_name>

      • 生成Interop Assembly

        • Struct/Union
        • Enum
        • Interface
        • Class
      • 直接引用即可

      • VS中Add Reference

    • 使用RCW

      • 创建RCW    MyRCW  rcw=new MyRCW();

      • 释放RCW     GC自动处理    AppDomain Unload 时候    Marshal.ReleaseComObject     Marshal.FinalReleaseComObject

      • 调用方法 rew.Func()

      • Cast

        • ImyInterface2  interface2=rcw as IMyInterface2; 可能成功
        • 实际上对应QueryInterface调用  
        • 不需要RCW类型本身实现IMyInterface2!
        • 失败则抛出异常(Cast)或者返回Null (as 操作符)
    • DEMO

        不会建立com 组件的请参考csdn上一位大牛的帖子  上面有详细的创建流程在此感谢大牛的分享 ,这里在分享一篇有心人收集的对应表 com 我个人感觉用的是Windows数据类型 自己参考查看 对应表

       

     c#代码片段

        class Program
        {
           
    
           
            [ComImport, Guid("31E95758-B52C-4252-B4E0-F33547F9B55A")]
    
            public interface IMyATLClass
            {
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(1)]
                void Add([In] int para1, [In] int para2);
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(2)]
                void PopupDialog(string text);
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)]
                void Sum([In] int para1, [In] int para2, out int Sum);
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(4)]
                void Messg([In] string test);
                
            }
    
            [ComImport, CoClass(typeof(MyATLClassClass)), Guid("31E95758-B52C-4252-B4E0-F33547F9B55A")]
            public interface MyATLClass : IMyATLClass
            {
            }
    
            [ComImport, Guid("D14CE5C7-9648-427B-BEAC-504E1A91DDAE")]
            public class MyATLClassClass : IMyATLClass, MyATLClass
            {
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(1)]
                public virtual extern void Add([In] int para1, [In] int para2);
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(2)]
                public virtual extern void PopupDialog([MarshalAs(UnmanagedType.BStr)] string text);
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(3)]
                public virtual extern void Sum([In] int para1, [In] int para2, out int Sum);
    
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(4)]
                public virtual extern void Messg([In] string test);
            }
            static void Main(string[] args)
            {
              //  MyATLComLib.IMyATLClass aa = new MyATLComLib.MyATLClass();
                //int i;
                //aa.Sum(1, 1, out i);
                //aa.Add(1, 1);
    
                //IntPtr sb = Marshal.StringToCoTaskMemAnsi("123");
    
    
                IMyATLClass aa = new MyATLClass();
                int i;
                aa.Sum(1, 1, out i);
                //aa.Add(1, 1);
    
              //  IntPtr sb = Marshal.StringToCoTaskMemUni("21");
                string a = "a";
                IntPtr aPtr = Marshal.StringToHGlobalAnsi(a);
    
                IntPtr helloPtr = Marshal.StringToHGlobalAnsi("aaaa");
              
              //  aa.PopupDialog("a1");
                aa.Messg("哈哈哈哈");
     
                Console.Write(i);
                Console.Read();
                //    int i;
                //     DemoObjectLib.IMyCOMDemo aaaa=    new DemoObjectLib.MyCOMDemoClass();
            }
        }

        c++代码片段

    // MyATLClass.cpp : CMyATLClass 的实现
    
    #include "stdafx.h"
    #include "MyATLClass.h"
    
    
    // CMyATLClass
    
    
    
    STDMETHODIMP CMyATLClass::Add(LONG para1, LONG para2)
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState());
        LONG a = para1 + para2;
        AfxMessageBox(a);
        // TODO:  在此添加实现代码
         return S_OK;
    }
    
    
    STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
        // TODO:  在此添加实现代码
        AfxMessageBox((LPCTSTR)text);
        return S_OK;
    }
    
    
    STDMETHODIMP CMyATLClass::Sum(LONG para1, LONG para2, LONG* sum)
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
        // TODO:  在此添加实现代码
        *sum = para1 + para2;
        return S_OK;
    }
    
    
    
    
    
    STDMETHODIMP CMyATLClass::Messg(BSTR test)
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
        // TODO:  在此添加实现代码
        AfxMessageBox(test);
        return S_OK;
    }

      

     

       

  • 相关阅读:
    Mvc5+Ef 6.0入门开发随笔(2.MVC的简单创建与使用图文详解)
    转载:CSDN mvc ef 的简单增删改查操作
    插件
    Jmeter-后置处理器--json提取器
    jmeter的几种参数化方式
    Python--变量命名规范
    Python--对list、tuple、dict的操作
    Python--列表中字符串按照某种规则排序的方法
    Python--遍历文件夹下所有文件和目录的方法(os.walk(rootdir)函数返回一个三元素元祖)
    Python--递归函数实现:多维嵌套字典数据无限遍历
  • 原文地址:https://www.cnblogs.com/kubimiantiao/p/6125678.html
Copyright © 2011-2022 走看看