ComAddin.Object.SomeMethod在一个项目中工作,但在另一个项目中不工作

时间:2016-05-10 11:12:58

标签: c# com vsto office-interop

我前段时间做了一个原型,使用VSTO并将其方法暴露给另一个项目。

现在我尝试将我当时成功的用途应用到我目前正在处理的项目中,但它不起作用。

我得到一个异常消息“System .__ComObjectenthältkeinefindicfürOpen。​​”,这在英语中意味着同样多,因为ComObject中没有定义。

我在这里做错了什么?

我检查了错误拼写,参考资料,如果我忘记实施我对原型所做的事情,但没有成功。

最初我指出了我在这个答案中实施的方式:

https://stackoverflow.com/a/35555413/3664953

虽然包含链接很棒并且确实有助于在VSTO工作,但我在这里找不到针对我的特定问题的解决方案。 我也检查了问题,这个答案指出:

https://stackoverflow.com/a/3690214/3664953

我尝试使用x86编译的二进制文件,并将Framework从4.5.2切换回4.5而不做任何更改。

€:好吧,行为有变化,使用x64编译的bin(我通常使用“Any CPU”),ComAddIn的Object中有一个null ...

我真的不知道这种行为在哪里开始,但也许你会这样做。

最后,什么是一个已经很糟糕的问题,可能只是因为我太靠近并且没有看到错误而没有破坏的代码而被创建。

所以就是这样,我从工作原型开始,还包括新代码。我削减了一点,所以现在两种解决方案中只有Open方法。

我这样做了,因为我知道这个问题已经很长了,我不想浪费你太多的时间。

原型看起来像这样:

的Controler:

static void Main(string[] args)
{
  Microsoft.Office.Interop.Word.Application wd = 
    new Microsoft.Office.Interop.Word.Application();
  wd.Visible = false;
  object addinName = "Worker_AddIn";
  foreach (Microsoft.Office.Core.COMAddIn comaddin in wd.COMAddIns)
  {
    if (comaddin.ProgId.Equals(addinName.ToString(), 
           StringComparison.InvariantCultureIgnoreCase))
    {
      object addinObj = comaddin.Object;
      object[] invokeArgs = { "Dummy" };

      object retVal = 
                    addinObj.
                        GetType().
                        InvokeMember("Open", System.Reflection.BindingFlags.InvokeMethod, 
                        null, addinObj, invokeArgs);

      //dynamics ...
      var t1 = comaddin.Object.Open("Dummy");
      var t2 = comaddin.Object.GetCustomProperties();
      var t3 = comaddin.Object.SetCustomProperty("Test",
                 PropertyTypes.msoPropertyTypeBoolean, 42);
    }
  }
  //Properly close Word
  wd.Quit();
}

外接程序:

PropertyReaderWriter及其接口:

public enum WordBuiltinProperties
{
  //some enums
}

public enum PropertyTypes
{
  //more enums
}

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IPropertyReadWriter
{
  bool Open(string Path);
  //There are more methods, but this one is already causing problems, 
  //also the others don't work either, so I kept the simplest one ;)
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class PropertyReaderWriter : StandardOleMarshalObject, IPropertyReadWriter
{
  public bool Open(string Path)
  {
    return false;
    //This was a test, if I could actually use those methods outside of VSTO, 
    //so I didn't implement logic, since I know the stuff I need works in VSTO.
  }
}

RequestComAddInAutomationService()的AddIn覆盖:

private IPropertyReadWriter rw;

protected override object RequestComAddInAutomationService()
{
  if (rw == null)
    rw = new PropertyReaderWriter();
  return rw;
}

计划类:

Microsoft.Office.Interop.Word.Application wd = 
  new Microsoft.Office.Interop.Word.Application();
wd.Visible = false;
object addinName = "Worker_AddIn";
foreach (Microsoft.Office.Core.COMAddIn comaddin in wd.COMAddIns)
{
  if (comaddin.ProgId.Equals(addinName.ToString(), 
       StringComparison.InvariantCultureIgnoreCase))
  {
    object addinObj = comaddin.Object;
    object[] invokeArgs = { "Dummy" };
    object retVal = addinObj.
                     GetType().
                     InvokeMember("Open", System.Reflection.BindingFlags.InvokeMethod, 
                                  null, addinObj, invokeArgs);
    //dynamics ...
    var t1 = comaddin.Object.Open("Dummy");
    var t2 = comaddin.Object.GetCustomProperties();
    var t3 = comaddin.Object.SetCustomProperty("Test", PropertyTypes.msoPropertyTypeBoolean,
                                               42);
  }
}
//Properly close Word
wd.Quit();

我项目中的实现看起来像这样。

使用接口我有一个名为IPropertyReadWrite_Word的派生接口,我在其中添加了一些方法,我不会覆盖。 我也使用IPropertyReadWrite_Word作为我的最终实现,但由于它是这个界面,定义“打开”我只发布这个以缩短极长的帖子。

接口:

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IPropertyReadWrite_Common
{
  /// <summary>
  /// Soll die Datei am entsprechenden Pfad öffnen.
  /// </summary>
  /// <param name="Path">Pfad zur Datei</param>
  /// <returns>Gibt Erfolg/true oder Misserfolg/false zurück.</returns>
  bool Open(string Path);
}

AddIn中的实现:

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Word_PropertyReadWrite : StandardOleMarshalObject, IPropertyReadWrite_Word
{
  internal static Word.Document Document;
  internal ThisAddIn home;

  /// <summary>
  /// Erzeugt die Klasseninstanz.
  /// </summary>
  /// <param name="home">Übergibt das ThisAddIn-Objekt, 
  /// um die Funktionen von Word verwenden zu können.</param>
  public Word_PropertyReadWrite(ThisAddIn home)
  {
    this.home = home;
  }

  /// <summary>
  /// Öffnet die Datei am entsprechenden Pfad.
  /// </summary>
  /// <param name="Path">Pfad zur Datei</param>
  /// <returns>Gibt bei Erfolg true zurück.</returns>
  public bool Open(string Path)
  {
    try
    {
        Document = home.Application.Documents.OpenNoRepairDialog(FileName: Path,
            ConfirmConversions: false, ReadOnly: false, AddToRecentFiles: false,
            Revert: false, Visible: false, OpenAndRepair: true, NoEncodingDialog: false);
        return true;
    }
    catch
    {
        //TODO: Logging
        //Rethrow der entstandenden Exception.
        throw;
    }
  }
}

覆盖RequestComAddInAutomationService():

私有Word_PropertyReadWrite PropertyReadWrite;

protected override object RequestComAddInAutomationService()
{
  //System.Diagnostics.Debugger.Break();
  if (PropertyReadWrite == null)
    PropertyReadWrite = new Word_PropertyReadWrite(this);
  return PropertyReadWrite;
}

最后,到目前为止,这是我的测试类:

static void Main(string[] args)
{
  Microsoft.Office.Interop.Word.Application wd = 
    new Microsoft.Office.Interop.Word.Application();
  wd.Visible = false;
  object addinName = "Dokumentenvorbereitung_Word_AddIn";
  try
  {
    Microsoft.Office.Core.COMAddIn addin = 
      wd.COMAddIns.Item(ref addinName);
    foreach (Microsoft.Office.Core.COMAddIn comaddin in wd.COMAddIns)
    {
      if (comaddin.ProgId.Equals(addinName.ToString(),
          StringComparison.InvariantCultureIgnoreCase))
      {
        var test = (comaddin).Object.Open(@"Path to some valid .docx");
      }
    }
  }
  catch(Exception e)
  {
    //...
  }
  finally
  {
    wd.Quit();
  }
}

1 个答案:

答案 0 :(得分:0)

好吧,我得到了一个解决方案,这有点奇怪,我在实现中添加了名为IPropertyReadWrite_Common的IPropertyReadWrite_Word的父接口。

现在我的标题看起来像这样:

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Word_PropertyReadWrite : StandardOleMarshalObject, IPropertyReadWrite_Common,
    IPropertyReadWrite_Word

现在它就像一个魅力,虽然我不确定,为什么它不应该开始工作......也许有人可以添加提示?

这是一种奇怪的行为,我有点怀疑,任何人都会在不久的将来遇到同样的问题,因为我的用例很奇怪:))

此时,我真的要感谢@Cindy Meister,你已经两次一次又一次地帮助了我这么奇怪的问题,谢谢你的耐心等待!