首页 > 其他分享 >公共语言运行库(CLR)开发系列课程(3):COM Interop基础 学习笔记

公共语言运行库(CLR)开发系列课程(3):COM Interop基础 学习笔记

时间:2023-07-04 09:11:12浏览次数:52  
标签:运行库 Interop void int InternalCall COM ComImport MethodCodeType

公共语言运行库(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;
}
复制代码

 

  

 

 

   

标签:运行库,Interop,void,int,InternalCall,COM,ComImport,MethodCodeType
From: https://www.cnblogs.com/ioriwellings/p/17524763.html

相关文章

  • autosys job use unix command
    AutosysvariablenotbeingsetinprofileAskedby:BadHatHarryIhavecreatedanautosysjob(thisisatestjob,theoriginalonealsohasthesameproblem)whereifIsourcetheprofilemanuallythevariable$HDG_RunPergetssetproperly,whereasw......
  • Combinatorics
    长期更新。CF626FGroupProjects写了。CF1580BMathematicsCurriculum答辩题\(n^5\)过100这个题目的条件是笛卡尔树的层数,考虑的意义是对于每个区间求LCA那么LCA必然处于\(i\)到根节点的链上。求的就是构建点的个数为\(n\),深度为\(m\)的儿子个数有\(k\)个......
  • How to use handleChange() function in react component?
    An onChange eventistriggeredwhenvaluesareenteredintheinput.Thisfiresafunction handleChange(),thatisusedtosetanewstatefortheinput.1.HandlingSingleInputFirst,wehavetosetuptheinputfieldasacontrolledcomponentsothatw......
  • Angular Component 里 get 关键字修饰的属性的用法
    在Angular中,get关键字用于定义一个访问器属性(accessorproperty),它是一种特殊的属性,可以通过在类中定义一个带有get关键字的方法来实现。当访问这个属性时,会调用这个get方法,并返回该方法的返回值。这种方法使得访问属性时可以执行一些自定义操作,例如计算属性值、验证数据或......
  • Angular Component 里使用 const 和 readonly 修饰的属性有什么区别
    在Angular组件中,我们可以使用const和readonly关键字来修饰成员属性。这两个关键字的目的都是为了确保数据的不变性,但它们在实现和用法上有很大的区别。在本文中,我们将详细讨论这两者之间的区别,并在不少于2800字的篇幅内进行深入分析。首先,让我们了解一下const和readon......
  • compareTo()方法
    1.返回参与比较的前后两个字符串的ASCII码的差值,如果两个字符串首字母不同,则该方法返回首字母的ASCII码的差值。Stringa1="a";Stringa2="c";System.out.println(a1.compareTo(a2));//结果为-22.参与比较的两个字符串如果首字符相同,则比较下一个字符,直到有不同的为止,......
  • Common BeanUtils组件的使用(源码)
    CommonBeanUtils组件方便了对JavaBean的使用。其中的一些类方法,使我们使用JavaBean得到了便利。 使用CommonBeanUtils组件需要三个Jar包,分别是commons-beanutils-1.8.0-BETA.jarcommons-logging-1.1.1.jarcommons-logging-api-1.1.1.jar 可从官网下载,不过为了方便,我把三个包传......
  • Compile result comparison
    Thesourcecodeasbelow#include<stdint.h>#include<stdio.h>typedefstruct{uint8_tdata1;uint8_tdata2;uint8_tdata3;uint8_tdata4;uint8_tdata5;}config_t;config_tgConfig[2]={0};uint8_tgIndex=0;confi......
  • 多个commit合并为一个
    在进行多个commit合并成一个博客编写的过程中,你可以使用以下代码示例作为参考:#合并多个commitgitrebase-iHEAD~N#N代表需要合并的commit数目,例如合并最近3个commit,N为3,也可以选择任意commit信息gitrebase-istartCommit[endCommit],默认endCommit是最新的commit,com......
  • Comparing with traditional convex optimization methodology, what are advantages
    与传统的凸优化方法相比,粒子群算法有哪些优点 与传统的凸优化方法相比,粒子群优化(PSO)算法具有以下优点:全局搜索能力:PSO算法具有较强的全局搜索能力,能够在多个解空间中寻找最优解。由于粒子群在搜索过程中可以通过信息共享和合作,有助于避免陷入局部最优解。适应性和......