公共語言運行庫(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數據類型 本身參考查看 對應表html

   

 c#代碼片斷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++代碼片斷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;
}

 

  

 

相關文章
相關標籤/搜索