2 Replies
      Latest reply on Jun 5, 2019 4:26 AM by wiristeam
      wiristeam Level 1 Level 1 (0 points)

        I have two processes that communicate using apple events. The first app is an electron nodejs app. The other one is a shim bundle attached to Microsoft Word that allows the user to insert OLE objects generated by my app. The shim has been developed in objective-c. When the user inserts an object in Microsoft Word, the shim calls my app and shows the object in a new window. The user can edit the object and save it. When the user saves the object, the app sends an Apple Event to Microsoft Word with the object information; the shim receives this information and inserts the object modified. The code in charge of this communication in both sides is:

        App side (programmed in objective-c++ as a native module of nodejs app)

         

        NSAppleEventDescriptor  *aeEvent = [NSAppleEventDescriptor
                    appleEventWithEventClass:kCustomCoreEventClass  // 'core'
                                     eventID:kAEEGOSetData      // 'setd'
                            targetDescriptor:clientAddressDesc
                                    returnID:kAutoGenerateReturnID
                               transactionID:kAnyTransactionID];
        //.... some more code to set important information ....
        //set data if it has changed
        if(dataChanged) {
          NSAppleEventDescriptor * imageDataDesc = [NSAppleEventDescriptor 
                       descriptorWithDescriptorType:dataType
                                              bytes:[data bytes] //NSData object containing data to send
                                             length:[data length]];
          [aeEvent setDescriptor:imageDataDesc
                      forKeyword:kKeyEGOData];     
        }
        //send event and free memory
        AppleEvent  reply;
        AESendMessage([aeEvent aeDesc], &reply, kAEWaitReply, kAEDefaultTimeout);

        Shim side (programmed in objective-c++)

        - (void)handleAppleEvent:(NSAppleEventDescriptor *)event
                  withReplyEvent:(NSAppleEventDescriptor *)replyEvent
        {
            //.... do some work with the event information....
            NSAppleEventDescriptor *imageData = [event paramDescriptorForKeyword:kDataKeyWord];
            //...keep working using the data obtained....
        }

        which has been previously installed using:

        [appleEventManager setEventHandler:self
                                   andSelector:@selector(handleAppleEvent:withReplyEvent:)
                                 forEventClass:kAECoreSuite // 'core'
                                    andEventID:kAESetData]; // 'setd'

         

        In the past, we treated differently information received from word and information received from other apps (such as Pages). For this reason, the keyword kKeyEGOData, which matches kDataKeyWord had been set to 'ShmD', while the interactions with other apps used the keyword 'data'.  However, now we have unified both codes. The app behaves equally when receiving information from Word than the rest of the apps. For this reason, we wish to change thes keywords to 'data'. The problem that I have is that when sending the event using the word 'data' instead of 'ShmD', the word app does not enter the handler function, even if kDataKeyWord has been set to 'data'. Why could this possibly happen?

         

        Edit:

        I have tried the exchange launching Microsoft Word with debugging activated. Here I attach the logs printed in the terminal related to these apple events:

        Send an event with 'ShmD' keyword to store the data:

        {core,setd target=myApp {Uniq=*****,----=obj (****),data=**** (***...)} returnID=****}
        #################### handleAppleEvent

         

        Where '#################### handleAppleEvent' is printed by 'printf()' at the beginning of the handle function. Therefore, the app receives the event with the data correctly set and enters the handle function.

         

        Send an event with 'data' keyword to store the data:

        {core,setd target=myApp {Uniq=*****,----=obj (****),data=**** (***...)} returnID=****}

         

        The event is correctly detected by Microsoft Word but it never reaches the handler.

         

        It does not matter in which order I send the events, the behavour is consistent. That is:

        • if I send an event with keyword 'data' it NEVER reaches the handler, even when preceeded by an event with data keyword 'ShmD'.
        • If I send an event with keyword 'ShmD' it ALWAYS reaches the handler, even when preceeded by an event with data keyword 'data'.
        • Re: Changing a parameter name breaks Apple Events communication
          hhas01 Level 1 Level 1 (20 points)

          I’m struggling to understand why your plugin is injecting a `core/setd` event handler. You realize Word, like most “AppleScriptable” apps, already installs a `core/setd` event handler as part of its standard interface? I *strongly* recommend your plugin assigns custom four-char-codes to its own handlers in order to avoid collisions with the host app’s own.

           

          General rule is that 4CCs containing all-lowercase chars are for Apple’s use, so always include at least one uppercase char in your own 4CCs, and check Word’s own dictionary to see what codes it uses so you can avoid those as well. (Open Word’s dictionary in Script Editor, then save to .sdef file and open that in any plaintext/XML viewer.)

            • Re: Changing a parameter name breaks Apple Events communication
              wiristeam Level 1 Level 1 (0 points)

              Thank you for the answer! This pointed me in a good direction. So now, one possible way to solve this is to simply implement a custom event. However:

               

              The reason why we override the 'core/setd' handler is because the default 'core/setd' handler works correctly for other applications. For example, in Pages, we are able to receive and send information with the default implementation. If we need to implement a completely different handler, we would have to always consider the Microsoft Word case differently, which is what we are originally trying to avoid.

               

              After reading your comment I have tried to:

              • Send the event using Word's default handler with the same parameters I set in Pages -> It does not work.
              • Follow this guide (with minor modifications) to test interaction with Microsoft Word -> I am able to write text in a new Microsoft Word from an Apple Script:
              set textVar to "Example first line" & return & "Example second line" --create text variable
              
              tell application "Microsoft Word" --telling MS Word to create a new document, as opposed to "active document"
                   create new document
                   set myRange to create range active document start 0 end 0 --now we are setting what the contents of text, for the whole document (myRange), should be, by calling our variable (fiHR) which we have previously defined
                   set content of myRange to textVar --this line sets our cursor/insertion point to the end of our text. it could be set to a character, word, line paragraph etc. Story is everything we have typed into the new doc. We do this, because we want the formatting to apply to all of the text typed in from our variable.
              endtell

              I launched Word with Apple Events debugging activated and run the script. Word is receiving a 'core/setd' event with attributes I yet have to understand, but my idea is to translate that information to objective-c and change the 'data' property of the received apple event to my object.

               

              Do you think it is a good idea?