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

本文关键字:接口 类型 任何 实现 返回 COM | 更新日期: 2023-09-27 18:11:15

我需要从。net 4.0应用程序自动执行adobeindesigncs3中的一些任务。我使用Visual Studio中的"添加引用"对话框为InDesign类型库添加了一个引用。它生成一个互操作程序集,该程序集正确地包含类型库中声明的所有接口和类型。我没有安装任何Adobe SDK,因为在Visual Studio中可以使用类型库,而不需要安装Adobe InDesign CS3。

对我来说,现在互操作汇编中有趣的类型是接口_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。据我所知,这完全正常。

现在,好戏开始了。为了使这个实例对我可用,我应该将它强制转换为正确的接口。从网络上的其他示例和这里提供的文档中,我可以看到我应该将其转换为Application接口。但如果我这样做,我得到一个讨厌的InvalidCastException说类型System.__ComObject不支持这个接口。如果我试图将其强制转换为ApplicationClass_Application接口,我会得到相同的异常。

我想我可能使用了一个不正确的接口,所以我尝试实现这里列出的实用函数。该函数循环遍历互操作程序集中声明的所有接口,并查询IUnknown接口是否实现了该接口。

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

然而,如果我用Visual Studio调试器检查instance变量,有一个叫做"动态视图"的东西。如果我展开它,它列出了对象的所有属性,并且所有属性都与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的人能知道我可能做错了什么。

提前感谢,很抱歉写了这么长一篇。

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

你必须使用一个运行时可调用的包装

你需要的方法是这个

Try this:

    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));
    }

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

为了摆脱这个错误,你需要注册COM对象通过做这些步骤(已经解释在这里)-这是InDesign CC2021 v16.0(它类似于其他版本)

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

之后就可以了。希望我对别人有所帮助!

我最近没有使用COM,但据我所知(并理解你的问题),你不能像这样转换ComObject:

   Application app = (Application)comObject;

,但你应该使用作为操作符:

    Application = comObject as Application;