COM返回未实现任何接口的类型

时间:2011-10-13 16:26:04

标签: c# .net com interop adobe-indesign

我需要从.NET 4.0应用程序中自动执行Adobe InDesign CS3中的某些任务。我使用Visual Studio中的“添加引用”对话框添加了对InDesign类型库的引用。它创建了一个interop程序集,它正确地包含了类型库中声明的所有接口和类型。我没有安装任何Adobe SDK,因为除了Adobe InDesign CS3之外,Visual Studio中没有安装任何类型库。

现在,interop程序集中有趣的类型是接口_ApplicationApplication,以及类ApplicationClass。以下是它们的定义,因此您可以看到它们之间的关系:

public interface _Application
{
    // Lots of properties and methods
}

public interface Application : _Application
{
    // Empty
}

public class ApplicationClass : _Application, Application
{
    // The same properties and methods as declared in _Application
}

我尝试像这样实例化COM对象:

Type oType = Type.GetTypeFromProgID("InDesign.Application.CS3");
if (oType != null)
{
    object instance = Activator.CreateInstance(oType);
}

此代码成功。我得到一个实例,但是名为__ComObject的类型。据我所知,这是完全正常的。

现在,这里的乐趣开始了。为了让这个实例可以使用,我应该将它转换为正确的接口。从网上的其他示例和documentation available here,我可以看到我应该将其转换为Application接口。但是,如果我这样做,我会得到一个讨厌的InvalidCastException,说类型System.__ComObject不支持此接口。如果我尝试将其强制转换为ApplicationClass_Application界面,我会得到相同的异常。

我以为我可能使用了错误的界面,所以我尝试实现效用函数listed here。此函数循环遍历interop程序集中声明的所有接口,并在IUnknown接口实现接口时查询它。

当我使用该函数时,它返回null,这意味着我从CreateInstance返回的实例支持interop程序集中接口的 none 。当然,这不可能是对的!?

但是,如果我使用Visual Studio Debugger检查instance变量,则会出现名为“Dynamic View”的内容。如果我展开它,它会列出对象的所有属性,所有属性都匹配ApplicationClass类和_Application接口的属性。所以我尝试使用Type.InvokeMember,这有效:

oType.InvokeMember("DoScript", BindingFlags.InvokeMethod, null, instance, oArguments, CultureInfo.InvariantCulture);

这实际上有效,但是像这样与COM对象进行交互会非常麻烦,而且我需要与COM对象进行很多交互,所以这不是真正可用的。我想我可以为COM对象创建一个包装器,但是这种方法违背了互操作程序集的目的,而且我不想创建700多个包装器类。

我已经搜索了很多,我找到了使用InDesign COM对象的教程和示例,但是它们都只是将实例转换为Application接口,但正如所解释的,这在我的情况下不起作用。

我还尝试了以下代码而不是上面的代码:

InDesign.Application app = new InDesign.Application();
app.Activate();

第一行成功,我得到ApplicationClass的实例,但是当它尝试执行第二行时,我得到一个InvalidCastException,指出ApplicationClass无法转换为接口_Application

我真的被逼到了这里,不知道下一步该尝试什么。我真的希望有更多经验的COM和.NET能够了解我可能做错了什么。

提前致谢,对不起这么长的帖子感到抱歉。

3 个答案:

答案 0 :(得分:2)

您必须使用Runtime Callable Wrapper

您需要的方法是this one

试试这个:

    Type oType = Type.GetTypeFromProgID("InDesign.Application.CS3");
    if (oType != null)
    {
        object instance = Activator.CreateInstance(oType);// or any other way you can get it
        Application app = 
            (Application)System.Runtime.InteropServices.Marshal.CreateWrapperOfType(instance, typeof(ApplicationClass));
    }

答案 1 :(得分:0)

我最近没有使用COM,但是到目前为止我记得(并理解你的问题)你不能像这样投射ComObject:

   Application app = (Application)comObject;

但您应该使用作为运算符:

    Application = comObject as Application;

答案 2 :(得分:0)

@Seb 解决方案是正确的解决方案,但是在处理它时,我遇到了错误“源对象无法转换为目标类型,因为它不支持所有必需的接口。” (正如@MikeKeskinov 在评论中所写)。

要消除该错误,您需要通过执行这些步骤来注册 COM 对象(已经解释了 here)-这是针对 InDesign CC2021 v16.0(其他版本类似)

  • 使用任务管理器关闭所有 InDesign 实例
  • 转到 C:\ProgramData\Adobe\InDesign\Version 16.0\en_US\Scripting Support\16.0 并将 tlb 文件重命名为 tlb.bak(或类似的名称,没关系)
  • 以管理员身份打开命令窗口 (CMD)
  • 转到 InDesign EXE 文件夹 C:\Program Files\Adobe\Adobe InDesign 2021
  • 启动命令indesign.exe -type
  • 将新创建的 tlb 文件引用到项目

在那之后它应该可以工作。希望我对某人有所帮助!