4

我需要从 .NET 4.0 应用程序自动执行 Adob​​e InDesign CS3 中的一些任务。我使用 Visual Studio 中的“添加引用”对话框添加了对 InDesign 类型库的引用。它生成一个互操作程序集,该程序集正确地包括在类型库中声明的所有接口和类型。我没有安装任何 Adob​​e SDK,因为类型库在 Visual Studio 中可用,除了 Adob​​e InDesign CS3 之外没有安装任何东西。

现在对我来说,互操作程序集中的有趣类型是接口_ApplicationApplicationApplicationClass。这是它们的定义,因此您可以看到它们之间的关系:

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接口,我会得到相同的异常。

我想我可能使用了不正确的接口,所以我尝试实现此处列出的实用程序功能。此函数循环遍历 interop 程序集中声明的所有接口,并查询 IUnknown 接口是否实现了该接口。

当我使用该函数时,它返回 null,这意味着我返回的实例不CreateInstance支持互操作程序集中的任何接口。肯定是这样吧!?

但是,如果我instance使用 Visual Studio 调试器检查变量,就会发现有一个叫做“动态视图”的东西。ApplicationClass如果我展开它,它会列出对象的所有属性,并且所有属性都与类和_Application接口中的属性匹配。所以我尝试使用Type.InvokeMember并且有效:

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

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

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

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

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

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

我真的被困在这里,不知道下一步该尝试什么。我真的希望对 COM 和 .NET 更有经验的人知道我可能做错了什么。

在此先感谢,并为这么长的帖子感到抱歉。

4

3 回答 3

2

您必须使用运行时可调用包装器

你需要的方法就是这个

试试这个 :

    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));
    }
于 2011-10-18T14:25:28.483 回答
1

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

要消除该错误,您需要通过执行这些步骤来注册 COM 对象(已在此处解释) - 这适用于 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 文件引用到项目中

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

于 2021-01-11T12:30:28.120 回答
0

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

   Application app = (Application)comObject;

但您应该使用as运算符:

    Application = comObject as Application;
于 2011-10-18T13:59:52.190 回答