为Mac Word 2011编写插件 - 如此接近...... AppleScript,Objective-C和Word

时间:2016-08-08 21:54:34

标签: cocoa applescript word-vba word-vba-mac

我试图让Mac Word faux-plugin工作,我遇到了一些奇怪的问题。对不起 - 文字墙传入!

我知道我在这里触及了几个伏都教主题的交集,所以请耐心等待。

我们有......

  1. Microsoft Word 2011 Mac
  2. 的AppleScript
  3. AppleScript的对象 -
  4. ...试图假装一个插件。我意识到这一点绝对不受支持。

    我的设置:

    • 操作系统:macOS El Capitan,Xcode 7
    • Word 2011(最新补丁)

    一天结束时,插件会操纵Word字段代码。它创建并编辑它们。有一个超级简单的用户界面来执行这样的操作,然后在创建/更新/删除功能的各个类中。

    理论是:

    1. 使用sdef导出Word AppleScript标头,然后使用sdp(脚本桥)创建Obj-C接口
    2. 在某些情况下(例如find),它与AppleScript-Objective-C桥接到AppleScript
    3. 编写Obj-C方法并查看控制器以向用户显示控件
    4. 通过XCode单元测试我实际上已经完成了所有工作。通过外部虚拟应用程序托管,一切运作良好。但我真正喜欢做的就是把它嵌入到Word中。

      所以我看了两个相似但不同的选项:

      1. 部署为框架,通过引用公共C接口(通过VBA)调用Framework
      2. 部署为框架,通过AppleScript调用(通过VBA ......)
      3. 他们关闭了,但......不太对劲。

        选项1 - 带有C接口的框架

        使用此方法,您可以创建公共C接口 进入您的框架并使用它们来创建视图控制器。您在Word中引用框架并可以调用公共C方法。因为您的框架更直接由Word托管,所以您必须将其编译为32位。

        步骤:

        1. 在您的框架中创建一个.m文件,并公开访问您的UI的公共方法(EX:" MyLibOpenCustomUI")。
        2. 在VBA中引用您的框架
        3. VBA Macro(OpenOurCustomUI)向您的公共C接口发送消息
        4. Private Declare Sub MyLibOpenCustomUI Lib "/Library/Frameworks/MyFramework.framework/MyFramework" ()
          
          Sub OpenOurCustomUI()
              Call MyLibOpenCustomUI
          End Sub
          

          的问题:

          这很好用,但对于Word字段代码的严重问题。这种行为非常不一致。

          1. 尝试访问字段的fieldText(又名"数据"来自Windows)将频繁返回data parameter is nil。 entry_index,range和其他组件似乎都很好。无论出于何种原因,fieldText似乎无法访问。
          2.   NSLog(@"fieldText : %@", [field fieldText]);//data parameter is nil
            
            1. 在那些你可以访问fieldText的情况下(我仍然不清楚这个偶尔如何/为什么会这样做),fieldText被“损坏”#34;经过256个字符后。我只能说"腐败"因为文本似乎从ascii文本转换为某种形式的unicode字符,并且在此之后似乎也被截断了。
            2. EX :(然后:"姓名"在256位置

              "Name":䜽芟㘱瑵飯ﶿṼﶿ璒澗瑸瑵ᕻ各

              当通过外部框架运行时,想到这可能是AppleScript-Objective-C位的奇怪行为,我实际上试图从Objective-C调出AppleScript(嵌入applescript,在Obj-C中编写包装器,然后加载脚本在运行时)。

              像这样......它只是试图返回给定字段的field text(通过数字索引)

                on getFieldDataForFieldAtIndex:theIndex
                  set theIndex to theIndex as integer
                  tell application "Microsoft Word"
                    set theField to field theIndex of active document
                    return field text of theField
                  end tell
                  return missing value
                end getFieldDataForFieldAtIndex:
              

              这给了我一个更有趣的错误: Microsoft Word got an error: Can’t get active document. (error -1728)

              所以 - 没有骰子。当它发挥作用时,我会腐败"字符串响应。但更多的时候我无法进入fieldText。

              我完全不知道为什么会失败,在这一点上我不得不相信它与这样的框架在与Word交互时的方式有关。哪个很臭,真的。我喜欢这个工作。

              选项2 - 带有osascript + AppleScript的框架

              使用这种方法,您可以使用vba调用osascript来调用托管UI的AppleScript(我知道......我知道......)。您将框架编译为64位。

              在这个版本中,Word字段工作正常 - 字符串看起来很棒,并且可以毫无问题地访问和设置所有字段fieldText属性。

              步骤:

              1. 参考VBA中的popen
              2. VBA宏(OpenMyUI)
              3. 调用osascript
              4. 调用AppleScript(OpenMyUI.scpt)调用公共方法"显示界面"在你的框架中
              5. Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long
                
                Sub OpenMyUI()
                    'this works from the VBA debugger
                    'I _cannot_ get it to work from the VBA when launched from a button in a document... 
                    'window closes immediately w/o input    
                    Dim scriptToRun As String
                    Dim output As String
                    Dim command As String
                    command = "osascript ~/Library/Application\ Scripts/com.microsoft.Word/OpenMyUI.scpt"
                    output = popen(command, "r")
                    'If you want this to stick around, you have to do something like...
                    'MsgBox "stick around, window"
                End Sub
                
                --reference our framework
                use framework "/Library/Frameworks/MyFramework.framework"
                property theWindowLauncher : class "MyWindowLauncher"
                
                on openMyUI(arg)
                    set theReturn to theWindowLauncher's openUpdateOutput
                    return theReturn
                end openSettings
                
                return openMyUI(1)
                

                的问题:

                有两个大人物:

                1. 当您通过按钮单击等调用sub时,UI将消失或永不显示。除非你随后打电话给" MsgBox'''"在VBA中。然后它出现了。但行为很奇怪 - 如果您在关闭对话框之前没有专注于自定义UI窗口,那么自定义UI就会消失。
                2. 比这更大,窗口(至少在我的机器上)变成了全局模态。这是我以前从未见过的。那肯定不好。
                3. 奇怪的是,通过Word VBA调试器可以很好地解决这个问题。实际上工作得很好。只是当你通过直接从宏调用sub来运行它时(比如点击按钮)。

                  非常非常接近这两个选项。只是不够近。我特别被FieldText古怪所困扰。

                  所以......我想知道。关于如何进行的任何创意?我意识到我在这里所做的事情已经超越了“好主意”的界限,"但我很乐意看到这项工作。

1 个答案:

答案 0 :(得分:1)

我仍然无法回答选项1(直接C库引用和损坏的Word字段)的问题,但对于选项2(通过osascript调用AppleScript),我发现窗口实际上是 出现了 - 但是在我所有的其他窗口后面(在所有应用程序中),所以我从未意识到它在那里。

解决方案(选项2):这是告诉窗口到达前台的问题,它已经工作了#34; - 尽管有一点需要注意,它现在是一个全局模态窗口(不需要)。

东西......

//wc is our window controller
NSWindow* theWindow = [wc window];
[theWindow setTitle:windowTitle];
[NSApp activateIgnoringOtherApps:YES];
[theWindow setLevel:NSMainMenuWindowLevel];
[theWindow makeKeyAndOrderFront: self];

[NSApp runModalForWindow: theWindow];

目前已经足够了#34;通过获得。不是任何人想要的,但好的。

我根本不喜欢这个过程(vba - > C popen - > osascript - > AppleScript - > obj-c类方法)。

  1. 这只是丑陋的。我知道它会在某个时候破裂。
  2. 全局模态窗口=超级超级糟糕。
  3. Word 2016 ...我还没有测试过,但我怀疑它会有问题。
  4. 为什么要通过popen - > osascript - > AppleScript的?对于我的生活,我无法让MacScript成功调用AppleScript文件。还尝试使用嵌入式AppleScript。都没有奏效。刚刚得到了正常的"错误5。"

    我的AppleScript使用use framework来完成这项工作,所以我的猜测是MacScript不支持这个(但这只是猜测)。其他测试AppleScript(文件或嵌入式)没有包含use framework(" Hello,World!")工作正常。

    稍后我可能会回过头来看看我是否可以通过将Word交互移动到某种外部设置来使选项1工作 - 这可能有助于绕过奇怪的数据"数据是nil"问题和定期无法获得活动文件。希望我更多地了解这一点。