新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论.NET,C#,ASP,VB技术
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 Dot NET,C#,ASP,VB 』 → 使用C#与返回一致数组的 COM 服务器互操作 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 12179 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 使用C#与返回一致数组的 COM 服务器互操作 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     admin 帅哥哟,离线,有人找我吗?
      
      
      
      威望:9
      头衔:W3China站长
      等级:计算机硕士学位(管理员)
      文章:5255
      积分:18406
      门派:W3CHINA.ORG
      注册:2003/10/5

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给admin发送一个短消息 把admin加入好友 查看admin的个人资料 搜索admin在『 Dot NET,C#,ASP,VB 』的所有贴子 点击这里发送电邮给admin  访问admin的主页 引用回复这个贴子 回复这个贴子 查看admin的博客楼主
    发贴心情 使用C#与返回一致数组的 COM 服务器互操作


    发信人: Nineteen (-_-#!), 信区: DotNET
    标  题: 使用C#与返回一致数组的 COM 服务器互操作
    发信站: BBS 水木清华站 (Tue Nov  4 08:47:38 2003), 转信

    这片文章解决了前几天我碰到的问题。:)

    本文的发布号曾为 CHS305990  
    本任务的内容
    概要  

    COM 服务器示例  
    对 COM Interop 方法的讨论  

    使用 Interop 程序集  
    为 COM 服务器使用 C# 声明  
    添加托管包装类
    参考
    概要
    本文逐步介绍如何与返回一致数组的 COM 服务器互操作。

    下面的文件可以从 Microsoft 下载中心下载:

    Confarrs.exe  

    有关如何下载 Microsoft 支持文件的其他信息,请单击下面的文章编号,查看 Microsoft 知识库中的文章:  
    119591 How to Obtain Microsoft Support Files from Online Services(如何从联机服务获取 Microsoft 支持文件)

    在发表当日 Microsoft 使用了最新的病毒检测软件以扫描此文件是否有病毒。一旦发表后,此文件就保存在安全服务器上,以防对它进行未经授权的更改。  

    返回页首  
    COM 服务器示例
    本示例中使用的服务器实现下面的接口: interface IComArrsObj : IDispatch
    {
       HRESULT GetArrOfLongs([in] LONG nStartIdx, [in,out] LONG* pnCnt,
                             [out,size_is(,*pnCnt)] LONG** ppArr);
       HRESULT GetArrOfUDTs ([in] LONG nStartIdx, [in,out] LONG* pnCnt,
                             [out,size_is(,*pnCnt)] MyUDT** ppArr);
       HRESULT MyNextLongs  ([in] LONG nReq, [out, size_is(nReq)] LONG *rgelt,
                             [out] LONG* pnFetched);
       HRESULT MyNextUDTs   ([in] LONG nReq, [out, size_is(nReq)] MyUDT* rgelt,
                             [out] LONG* pnFetched);
    };
    如此接口规范所示,本文介绍如何与返回 Long 值和用户定义类型 (UDT) 的数组的 COM 服务器互操作。 该代码还演示了服务器分配的数组(即 GetArrOfXxx 方法)和客户端分配的数组(即 MyNextXxx 方法,它们模仿 IEnumXxx 接口中的 Next 方法)之间的区别。  

    GetArrOfXxx 方法使用下面三个参数:  
    nStartIdx 是一个 [in] 参数,它指定传递回客户端的第一个元素的索引。  
    pnCnt 是一个 [in, out] 参数,它等于客户端在进入时请求的项数,以及服务器在退出时提供的项数。 如果在进入时 pnCnt 为 0,那么服务器就返回所有可用的元素。  
    ppArr 是一个由服务器分配的 [out] 数组。 其大小等于 *pnCnt。  
    MyNextXxx 方法使用下面三个参数:  
    nReq 是一个 [in] 参数,它指定客户端请求的项数。  
    rgelt 是一个 [out] 参数,它由客户端分配并由服务器填充。 只有第一个 *pnFetched 元素是有效的。  
    pnFetched 是一个 [out] 参数,它指定由服务器填充的项数。  
    返回页首  
    对 COM Interop 方法的讨论
    通常,在与 COM 服务器互操作时,有下面几种选择:  
    使用 interop 程序集与 COM 服务器通讯。 如果有主 interop 程序集,则应使用该程序集。 否则,可以使用 Tlbimp.exe 实用工具或 Visual Studio .NET 的导入功能生成 interop 程序集。  
    直接在 Visual C# .Net 源代码中声明 COM 对象和接口。 如果需要与 COM 服务器公开的有限个对象和接口互操作,则可使用此选项。  
    您可以增强上面任一选择,做法是:添加一个托管类,该类为与 COM 服务器互操作所需要的粗略导入类提供一个熟悉的托管接口。  
    如果有主 interop 程序集,则始终应使用该程序集,因为主 interop 程序集提供一个经过充分测试的,经证明可靠的 interop 层来访问 COM 服务器功能。 在主 interop 程序集可用时,仍可以选择第三种方式,并为主 interop 程序集导出的类型提供托管接口。  

    在主 interop 程序集不可用时,所选择的方式取决于应用程序是否需要公开从 COM 服务器导入的类型。 在应用程序包括多个程序集,而这些程序集交换从 COM 服务器导入类型的数据时,可能会发生这种情况。  

    如果托管应用程序包含多个程序集,而这些程序集使用 COM 服务器并且需要公开从 COM 服务器导入的数据类型,则应使用共享程序集来定义 interop 程序集。 在这种情况下,强烈建议使用主 interop 程序集。  

    如果不需要在各程序集间公开 COM 服务器中的数据类型,则可以为 interop 程序集使用私有程序集(第一种选择)或者在 Visual C# .Net 代码中定义 COM 类型(第二种选择)。

    有关更多信息,请访问下面的 Microsoft Developer Network (MSDN) Web 站点:  
    Deploying an Interop Application(部署 Interop 应用程序)
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpcondeployinginteropapplication.asp

    返回页首  
    使用 Interop 程序集
    如果有主 interop 程序集,则始终应使用该程序集。 使用主 interop 程序集提供了一个经过充分测试的,经证明可靠的 interop 层来访问 COM 服务器功能。 此外,Tlbimp.exe 提供了一种自动生成 interop 程序集的方法,自动生成代码具有一些优点,如速度快,正确率高。 此外,当托管客户端需要访问由 COM 服务器公开的大量方法和接口时,则不能使用第二种选择。 在这些情况下,可以使用 interop 程序集访问 COM 服务器所提供的功能。 可以使用下列方法之一获取 interop 程序集:  
    从发布 COM 服务器(需要与其互操作)的软件供应商获取主 interop 程序集。  
    从 Visual Studio .NET 生成主 interop 程序集。 若要调用 Tlbimp.exe 生成需要的 interop 程序集,请单击项目菜单上的添加引用,单击 COM 选项卡,然后选择 COM 服务器的条目。  
    手动生成 interop 程序集。 为此,在 COM 服务器类型库(即 .tlb、.dll、.ocx 或 .exe 文件)上调用 Tlbimp.exe。 与依赖 Visual Studio .NET 的默认命令行参数相比,这使您对 Tlbimp.exe 有更好的控制。  
    为了获得最大的灵活性,请按照下列步骤操作:  

    使用 Tlbimp.exe 生成 interop 程序集的第一个版本,然后在该程序集上运行 Ildasm.exe。 为此,在命令提示符处键入 ildasm Interop.Srvr.dll /out=Interop.Srvr.il。  
    手动编辑生成的中间语言代码以指定所需要的封送处理行为。  
    使用 Ilasm.exe 获取项目中引用的最后一个 interop 程序集,重新汇编中间语言代码。 为此,在命令提示符处键入 ilasm /dll Interop.Srvr.il /out=Interop.Srvr.dll。  
    由于 COM 类型库格式的局限性,Tlbimp.exe 无法为本文示例中的 COM 服务器生成正确的接口定义。 因此,本文中的示例使用第四种选择。 若要使用此选择,请按照下列步骤操作:  
    在 COM 服务器动态链接库 (DLL) 上运行 Tlbimp.exe,如下所示:  
       > tlbimp /out:Interop_1.ComArrs_1_0.DLL /namespace:ComArrs_1 ComArrs.DLL  
    在生成的 DLL 上运行 Ildasm.exe,如下所示:  
       > ildasm /out=Interop_1.ComArrs_1_0.IL Interop_1.ComArrs_1_0.DLL
    在生成的中间语言文件中修改方法签名,以便根据您的需要修改封送处理。 每个方法在中间语言中都出现两次,因此必须在接口的声明和类的声明中进行这些更改:    .method public hidebysig newslot virtual abstract  
               instance void  GetArrOfLongs([in] int32 nStartIdx,
                                            [in][out] int32& pnCnt,
                                            // Replace this: [out] native int ppArr) runtime managed internalcall
                                            // with this:
                                            [out] native int& ppArr) runtime managed internalcall
       .method public hidebysig newslot virtual abstract  
               instance void  GetArrOfUDTs([in] int32 nStartIdx,
                                           [in][out] int32& pnCnt,
                                           // Replace this: [out] valuetype ComArrs_1.MyUDT&  marshal( lpstruct) ppArr) runtime managed internalcall
                                           // With this:
                                           [out] native int& ppArr) runtime managed internalcall
       .method public hidebysig newslot virtual abstract  
               instance void  MyNextLongs([in] int32 nReq,
                                     // Replace this: [out] int32& rgelt,
                                     // With this:
                                     [out] int32[] marshal([ + 1]) rgelt,
                                     [out] int32& pnFetched) runtime managed internalcall
       .method public hidebysig newslot virtual abstract  
               instance void  MyNextUDTs([in] int32 nReq,
                                         // Replace this: [out] valuetype ComArrs_1.MyUDT& rgelt,
                                         // With this:
                                         [out] valuetype ComArrs_1.MyUDT[] marshal([ + 1]) rgelt,
                                         [out] int32& pnFetched) runtime managed internalcall
    使用 Ilasm.exe 重新生成 interop 程序集,如下所示:    > ilasm /dll /resource=Interop_1.ComArrs_1_0.res Interop_1.ComArrs_1_0.il /out=Interop_1.ComArrs_1_0.dll
    在 Visual C# .Net 客户端项目中引用新的 interop 程序集。 为此,请单击项目菜单上的添加引用,然后浏览到最近生成的 DLL。  
    在托管客户端编写测试代码,如下所示:    public static void Run ( )
       {
          Console.WriteLine ( "\nTesting hand-edited IL of TlbImp-ed COM class:" );
          Console.WriteLine (   "=============================================:" );

          Console.WriteLine ( "Creating COM object" );
          ComArrs_1.CComArrsObj o = new ComArrs_1.CComArrsObj ( );

          Console.WriteLine ( "Calling GetArrOfLongs( )" );
          int cnt = 0;
          IntPtr rAddr;
          o.GetArrOfLongs ( 0, ref cnt, out rAddr );
          int [ ] r = new int [ cnt ];
          // Marshal the array from an unmanaged to a managed heap.
          Marshal.Copy ( rAddr, r, 0, cnt );
          // Release the unmanaged array.
          Marshal.FreeCoTaskMem ( rAddr );
          Utils.PrintArray ( r, elementFormatter );

          Console.WriteLine ( "Calling GetArrOfUDTs( )" );
          cnt = 0;
          IntPtr ruAddr;
          o.GetArrOfUDTs ( 0, ref cnt, out ruAddr );
          ComArrs_1.MyUDT [ ] ru = new ComArrs_1.MyUDT [ cnt ];
          // Marshal the array, element by element, from an unmanaged to a managed heap.
          for (int i = 0, elemOffs = (int) ruAddr; i < cnt; i++ )
          {
              ru[i] = ( ComArrs_1.MyUDT ) Marshal.PtrToStructure (
                             (IntPtr) elemOffs, typeof ( ComArrs_1.MyUDT ) );
              elemOffs += Marshal.SizeOf ( typeof ( ComArrs_1.MyUDT ) );
          }
          // Release the unmanaged array.
          Marshal.FreeCoTaskMem ( ruAddr );
          Utils.PrintArray ( ru, elementFormatter );

          Console.WriteLine ( "Calling MyNextLongs( )" );
          int [ ] q = new int [ 20 ];
          // The marshalling is performed automatically.
          o.MyNextLongs ( q.GetLength(0), q, out cnt );
          Utils.PrintArray ( q, elementFormatter );

          Console.WriteLine ( "Calling MyNextUDTs( )" );
          ru = new ComArrs_1.MyUDT[20];
          // The marshalling is performed automatically.
          o.MyNextUDTs ( ru.GetLength(0), ru, out cnt );
          Utils.PrintArray ( ru, elementFormatter );
       }
    返回页首  
    为 COM 服务器使用 C# 声明
    与使用 interop 程序集相比,此选择的优势在于消除了提供另一个文件(即 interop 程序集)的必要。  

    若要指定必需的元素并调用方法,请按照下列步骤操作:

    备注: 由“COM 服务器示例”部分提供的 COM 接口开始。  
    如下所示定义 UDT:  
       // MyUDT as defined in the server.
       [Guid("190A418D-B113-40d4-A22C-20EF9EAC3E33")]
       [StructLayout(LayoutKind.Sequential)]
       struct MyUDT
       {
          [MarshalAs(UnmanagedType.BStr)]
          public string   aBstr;
          public int      aLong;
          public bool     aBool;
       }
    如下所示定义 COM 接口:  
       // A possible C# representation of the interface.
       [InterfaceType(ComInterfaceType.InterfaceIsDual),
          Guid("78D4F391-B10B-4B80-A2D1-1B4C583DCAEC")]
       interface IComArrsObj
       {
          void GetArrOfLongs(int startIdx, ref int cnt, out IntPtr arrAddr);
          void GetArrOfUDTs (int startIdx, ref int cnt, out IntPtr arrAddr);
          void MyNextLongs  (int req,
                             [MarshalAs(UnmanagedType.LPArray, Out]
                             int [ ] rgelt,
                             out int fetched);
          void MyNextUDTs   (int req,
                             [MarshalAs(UnmanagedType.LPArray, Out]
                             MyUDT [ ] rgelt,
                             out int fetched);
       }
    如下所示定义 COM 服务器:    // The coclass.
       [ComImport, Guid("056A32CF-D716-4902-BCD2-ED7F070D9E36")]
       class CComArrsObj
       {
       }
    如下所示在 COM 服务器上调用方法:    public static void Run ( )
       {
          Console.WriteLine ( "\nTesting C#-declared COM class and interfaces:" );
          Console.WriteLine (   "============================================:" );

          Console.WriteLine ( "Creating COM object" );
          ComArrs_0.IComArrsObj icao = new ComArrs_0.CComArrsObj ( )
                                           as ComArrs_0.IComArrsObj;

          Console.WriteLine ( "Calling GetArrOfLongs( )" );
          int cnt = 0;
          IntPtr rAddr;
          icao.GetArrOfLongs ( 0, ref cnt, out rAddr );
          int [ ] r = new int [ cnt ];
          // Marshal the array from an unmanaged to a managed heap.
          Marshal.Copy ( rAddr, r, 0, cnt );
          // Release the unmanaged array.
          Marshal.FreeCoTaskMem ( rAddr );
          Utils.PrintArray ( r, elementFormatter );

          Console.WriteLine ( "Calling GetArrOfUDTs( )" );
          cnt = 0;
          IntPtr ruAddr;
          icao.GetArrOfUDTs ( 0, ref cnt, out ruAddr );
          ComArrs_0.MyUDT [ ] ru = new ComArrs_0.MyUDT [ cnt ];
          // Marshal the array, element by element, from an unmanaged to a managed heap.
          for ( int i = 0, elemOffs = (int) ruAddr; i < cnt; i++ )
          {
             ru[i] = ( ComArrs_0.MyUDT ) Marshal.PtrToStructure (
                            (IntPtr) elemOffs, typeof ( ComArrs_0.MyUDT ) );
             elemOffs += Marshal.SizeOf ( typeof ( ComArrs_0.MyUDT ) );
          }
          // Release the unmanaged array.
          Marshal.FreeCoTaskMem ( ruAddr );
          Utils.PrintArray ( ru, elementFormatter );

          Console.WriteLine ( "Calling MyNextLongs( )" );
          int [ ] q = new int [20];
          // The marshalling is performed automatically.
          icao.MyNextLongs ( q.GetLength(0), q, out cnt );
          Utils.PrintArray ( q, elementFormatter );

          Console.WriteLine ( "Calling MyNextUDTs( )" );
          ru = new ComArrs_0.MyUDT [20];
          // The marshalling is performed automatically.
          icao.MyNextUDTs ( ru.GetLength(0), ru, out cnt );
          Utils.PrintArray ( ru, elementFormatter );
       }
    返回页首  
    添加托管包装类
    托管包装类可以基于前面两个选择中的任何一个。 它可以使用第一个选择中 TlbImp 生成的包装,也可以封装对 COM 服务器的 Visual C# .Net 声明的引用。 若要使用后一个选择来生成托管包装类,请按照下列步骤操作:  
    添加一个对包含 COM 服务器的托管定义的 interop 程序集的引用。  
    依据 TlbImp 生成的类定义托管包装类,如下所示:  
       class MgdComArrs
       {
          public MgdComArrs ( )
          { cao_ = new ComArrs_1.CComArrsObj( ); }

          public int [ ] GetArrOfLongs ( int startIdx, ref int cnt )
          {
             IntPtr rAddr;
             cao_.GetArrOfLongs ( startIdx, ref cnt, out rAddr );
             int [ ] r = new int [ cnt ];
             // Marshal the array from an unmanaged to a managed heap.
             Marshal.Copy ( rAddr, r, 0, cnt );
             // Release the unmanaged array.
             Marshal.FreeCoTaskMem ( rAddr );

             return r;
          }

          public ComArrs_1.MyUDT [ ] GetArrOfUDTs ( int startIdx, ref int cnt )
          {
             IntPtr ruAddr;
             cao_.GetArrOfUDTs ( startIdx, ref cnt, out ruAddr );
             ComArrs_1.MyUDT [ ] ru = new ComArrs_1.MyUDT [ cnt ];
             // Marshal the array, element by element.
             for ( int i = 0, elemOffs = (int) ruAddr; i < cnt; i++ )
             {
                ru[i] = (ComArrs_1.MyUDT) Marshal.PtrToStructure (
                              (IntPtr) elemOffs, typeof ( ComArrs_1.MyUDT ) );
                elemOffs += Marshal.SizeOf ( typeof ( ComArrs_1.MyUDT ) )'
             }
             // Release the unmanaged array.
             Marshal.FreeCoTaskMem ( ruAddr );

             return ru;
          }

          public int MyNextLongs ( int req, int [ ] r )
          {
             int fetched;
             cao_.MyNextLongs ( req, r, out fetched );
             return fetched;
          }

          public int MyNextUDTs ( int req, ComArrs_1.MyUDT [ ] r )
          {
             int fetched;
             cao_.MyNextUDTs ( req, r, out fetched );
             return fetched;
          }

          private ComArrs_1.CComArrsObj cao_;
       }
    如下所示编写客户端代码:  
       public static void Run ( )
       {
          Console.WriteLine ( "\nTesting managed wrapper definition of COM class:" );
          Console.WriteLine (   "===============================================:" );
          Console.WriteLine ( "Creating managed wrapper" );
          MgdComArrs mcao = new MgdComArrs( );

          Console.WriteLine ( "Calling GetArrOfLongs( )" );
          int cnt = 0;
          int [ ] r = mcao.GetArrOfLongs ( 0, ref cnt );
          Utils.PrintArray ( r, elementFormatter );

          Console.WriteLine ( "Calling GetArrOfUDTs( )" );
          cnt = 0;
          ComArrs_1.MyUDT [ ] ru = mcao.GetArrOfUDTs ( 0, ref cnt );
          Utils.PrintArray ( ru, elementFormatter );

          Console.WriteLine ( "Calling MyNextLongs( )" );
          int [ ] q = new int [ 15 ];
          mcao.MyNextLongs ( q.GetLength ( 0 ), q );
          Utils.PrintArray ( q, elementFormatter );

          Console.WriteLine ( "Calling MyNextUDTs( )" );
          ru = new ComArrs_1.MyUDT [ 5 ];
          mcao.MyNextUDTs ( ru.GetLength ( 0 ), ru );
          Utils.PrintArray ( ru, elementFormatter );
       }

    --
    ——长夜漫漫,无心睡眠……难道狼妹妹也睡不着吗?


    ※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.206.3.3]
    上一篇
    返回上一页
    回到目录
    回到页首


       收藏   分享  
    顶(0)
      




    ----------------------------------------------

    -----------------------------------------------

    第十二章第一节《用ROR创建面向资源的服务》
    第十二章第二节《用Restlet创建面向资源的服务》
    第三章《REST式服务有什么不同》
    InfoQ SOA首席编辑胡键评《RESTful Web Services中文版》
    [InfoQ文章]解答有关REST的十点疑惑

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2004/11/9 2:25:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 Dot NET,C#,ASP,VB 』的所有贴子 点击这里发送电邮给Google AdSense  访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/4/24 18:38:51

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    109.375ms