zoukankan      html  css  js  c++  java
  • 为什么无法从外部访问VSTO对象?

    为什么要从外部获取VSTO对象?

      通常的场景是我们用VSTO创建了一个office应用程序,里面用托管代码定义了一些方法,我们想通过外部程序打开该VSTO程序,获取VSTO对象引用,然后调用这些方法,以达到控制Office文档的目的。

    直接获取失败

      以下代码试图从外部程序获取VSTO对象引用,然而失败了!

    using System;
    
    using System.Diagnostics;
    
    using System.Globalization;
    
    using System.IO;
    
    using System.Reflection;
    
    using System.Threading;
    
    using Microsoft.Office.Tools.Excel.Extensions;
    
    using IExcel = Microsoft.Office.Interop.Excel;
    
    using TExcel = Microsoft.Office.Tools.Excel;
    
    namespace ClientApplication
    
    {
    
       class Program
    
       {
    
          static int Main(string[] args)
    
          {
    
             /* To avoid any problem (exception of type "Invalid format") when manipulating the 
    
              * workbook, we'll specify here the culture en-US to avoid forcing the client to 
    
              * have a language pack for excel
    
              */
    
             Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
    
             //Get the application and set it visible (ie, seeing the excel front end)
    
             IExcel.Application application = new IExcel.Application();
    
             application.Visible = true;
    
             //Let's create the path to the file and then : open it
    
             string basePath = @"D:\Projects\PDA - Blog\Blog Research\VSTO - WCF\ServerApplication";
    
             string fileName = "ServerApplication.xlsx";
    
             IExcel.Workbook book = application.Workbooks.Open(Path.Combine(basePath, fileName),
    
                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
    
                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
    
                Type.Missing, Type.Missing, Type.Missing, Type.Missing);
    
    
             /* Let's now use the .NET 3.5 SP1 functionality to convert an interop
    
              * object to a VSTO object
    
              * As it is an extension method, we could also use
    
              * TExcel.Workbook workbook = book.GetVstoObject();
    
              */
    
             TExcel.Workbook workbook = WorkbookExtensions.GetVstoObject(book);
    
             //Let's now check that the conversion did work
    
             Debug.Assert(workbook != null, "The conversion to VSTO did not work");
    
             //It will fail ! 
    
             return 0;
    
          }
    
       }
    
    }

      也就是说我们从VSTO程序外部,试图获取的VSTO对象总是为空!

    原因其实很简单:

      我们在试图获取另一个进程中的对象引用,而一个进程是不可以直接访问另一个进程的内存空间的。这个道理我们都知道,我们对进程间通讯的方法也耳熟能详,什么消息发送、命名管道、匿名管道、共享内存和Socket等。令我们不解的往往是:既然能取得Interop的Appliction、WorkBook等对象,为什么不能取得托管的VSTO对象呢?如果我们了解COM就不难理解了,.net与office的Com的互操作其实也是进程间的一种通信机制,只不过是通过COM组件掩盖了底层的通信机制,看来进程间通信的最高境界就是通过COM组件的方式。也就是说Interop的Appliction等对象是由COM接口公开出来的,本例中后台其实启动了一个Excel进程作为COM服务器,我们的外部程序,本例中的命令行程序充当了一个COM客户端。而我们的VSTO对象没有公开为COM可见的形式。

    MSDN的解释:

      其实本文所说的VSTO对象,在MSDN的官方名称是宿主控件和宿主项。通过编程方式在运行时创建宿主项是有限制的,参加MSDN文章:Programmatic Limitations of Host Items and Host Controls

      大体意思是很多宿主项只能在设计时创建,运行时不能创建。

    如何实现从外部调用VSTO程序的托管方法呢?

      答案就是使用进程间通信,有兴趣的可以参考这篇文章:http://www.pedautreppe.com/post/How-can-we-manipulate-the-VSTO-objects-when-opening-a-VSTO-document-from-command-line-.aspx  ,是通过.net remoting实现的。

    参考资料

    COM互操作教程

    可以通过OLE-COM Object Viewer查看COM组件公开的接口

  • 相关阅读:
    Android 自定义RadioButton的样式
    利用ListView批量删除item
    android中checkbox自定义样式
    Android 限定符
    Android Fragment的用法(二)
    Android Fragment的用法(一)
    Android 自定义控件
    Android 外部启动activity,自定义action,action常量大全
    Android之编写测试用例
    Android 定制自己的日志工具
  • 原文地址:https://www.cnblogs.com/slmk/p/2456831.html