Apple Event: May 7th at 7 am PT

Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Microsoft Word API for Mac OS: Is it possible using Objective-C?

I am writing a program which needs to "connect" to Ms-Word: in the opened file, I need to search for text, change and format it, add field codes etc.
Thus I need the API of Word for Mac to do all that.

The only thing I have found so far is AppleScript, which can do some manipulations on word documents.

Although I don't know whether AppleScript will be enough to do my job fully and efficiently.
Also, **what is important**, this AppleScript script must be integrated into my Cocoa application (call it from other modules, it also should return some values to the main code).

*Does anyone know whether the AppleScript is the only way to manipulate Ms-word from within the Cocoa application?
Is there a possibility to do it directly using Cocoa/Objective-C? *

MacBook, iMac, iPhone, Mac OS X (10.6.4)

Posted on Oct 22, 2010 3:53 PM

Reply
Question marked as Best reply

Posted on Oct 22, 2010 4:24 PM

There is a Java library for it, so I would be extremely surprised if there was not a C library that can deal with office documents.
13 replies

Oct 30, 2010 9:40 AM in response to DavidMan

Wow! I managed to create the .h header file for the Word and added it to the project. That worked.. not really well but still.
The problem is that the recommended command:
*sdef ./Microsoft\ Word.app/ | sdp -fh --basename word*
does not produce valid .h file because enumerators e183 and e315 had missing "name" values (e183: 1, e315: all were missing).

Therefore, I performed the commands separately:
*sdef ./Microsoft\ Word.app/ > word.sdef*
*cat word.sdef | sdp -fh --basename word*
Errors found in 1.txt were corrected manually (Just added "my own" "name" fields).
Thus I have Word.h which is functional
The communication with Ms-Word works: I can check whether it's running and if not, activate it.

Now what I want to do is:
1. Find the text of certain pattern (somehow have to use regular expressions)
2. Process the found text and replace it with the field code, which can be found later and which will show different text, whatever I tell it to show.

But I got stuck on the first step 😟
Word has MicrosoftWordTextRange class (in my Word.h it is WordTextRange):
@property (copy, readonly) WordFind *findObject;
It returns the find object associated with this text range.
I don't know why, but most of @properties are readonly.

WordTextRange has a property of class WordFind, which returns the find object associated with this text range.
WordFind, on the other hand, has the ONLY method executeFindFindText which has many settings, runs the specified find operation and returns true if the find operation is successful.

As I understand, I should define text range of the document and then execute the find.
So, I have a pretty simple code:
=========
wordApp=[SBApplication applicationWithBundleIdentifier:@"com.microsoft.Word"];
if ([wordApp isRunning]){
WordDocument *activeWordDoc=[wordApp activeDocument];
WordTextRange *allTextRange=[activeWordDoc textObject];

[findObj executeFindFindText:@"FirstText"
matchCase:NO
matchWholeWord:YES
matchWildcards:NO
matchSoundsLike:NO
matchAllWordForms:NO
forward:YES
wrapFind:NO
findFormat:NO
replaceWith:@"SecondText"
replace:YES
];
=========

*It tells me: -[MicrosoftWordFind executeFindFindText:]: unrecognized selector sent to instance.
Why?*
(I wrote the same code for the WordFind object of the WordTextSelection class but the result is the same)

This is the AppleScript equivalent of the above code:
=========
tell application "Microsoft Word"
set findRange to find object of selection
tell findRange
execute find find text "FirstText" replace with "SecondText" replace replace all
end tell
end tell
=========
and it works!

I am just stuck and don't know what to do...
Is it possible to browse "live" object and see what methods and properties does it have? I want to somehow see what do the objects have in reality.
Debugger is so complicated with its nested entries... I tried to install F-Script but could not manage it from the first try and just left it.

Oct 30, 2010 10:40 AM in response to DavidMan

DavidMan wrote:

wordApp=[SBApplication applicationWithBundleIdentifier:@"com.microsoft.Word"];
if ([wordApp isRunning]){
WordDocument *activeWordDoc=[wordApp activeDocument];
WordTextRange *allTextRange=[activeWordDoc textObject];
[findObj executeFindFindText:@"FirstText"
matchCase:NO
matchWholeWord:YES
matchWildcards:NO
matchSoundsLike:NO
matchAllWordForms:NO
forward:YES
wrapFind:NO
findFormat:NO
replaceWith:@"SecondText"
replace:YES
];


*It tells me: -[MicrosoftWordFind executeFindFindText:]: unrecognized selector sent to instance.
Why?*


Where do you define "findObj"?

It seems like you need:

wordFind * findObj = [allTextRange findObject];

Oct 30, 2010 12:53 PM in response to DavidMan

It looks like your method signature isn't correct. You also don't seem to have the correct enums. It should be something more like this:

[findObj
executeFindFindText: @"FirstText"
matchCase: NO
matchWholeWord: YES
matchWildcards: NO
matchSoundsLike: NO
matchAllWordForms: NO
matchForward: YES
wrapFind: wordE265FindContinue
findFormat: NO
replaceWith: @"SecondText"
replace: wordE273ReplaceAll];

Oct 30, 2010 1:21 PM in response to etresoft

@etresoft

After typing just
[findObj e
XCode automatically extends it to the complete syntax of executeFindFindText method, meaning that it recognizes the function.

You are right, there should be enums.
But even if I just write
[findObj executeFindFindText: @"FirstText"];
i.e. give just one essential argument to it and omit all the others (accept defaults), the result is the same: Error of "Unrecognized selector"


P.S. two side questions:
1. how to post the text here as code?
2. how to upload my Word.h file so that you can have a better idea what's going on?

Oct 30, 2010 2:17 PM in response to DavidMan

DavidMan wrote:
After typing just
[findObj e
XCode automatically extends it to the complete syntax of executeFindFindText method, meaning that it recognizes the function.


Perhaps you mis-typed one of those parameters. In your original version the "forward" should have been "matchForward". That would cause the error.

You are right, there should be enums.
But even if I just write
[findObj executeFindFindText: @"FirstText"];
i.e. give just one essential argument to it and omit all the others (accept defaults), the result is the same: Error of "Unrecognized selector"


It doesn't work that way. All parameters must be specified.

P.S. two side questions:
1. how to post the text here as code?


Wrap it between two lines of:


2. how to upload my Word.h file so that you can have a better idea what's going on?


Just double-check it on your own copy first. It is possible I could have a different version. I built it the same way you did. I have Office 2008. It is a big file, you don't want to post the whole thing.

Oct 30, 2010 6:19 PM in response to etresoft

Here is the final version of the code:

{code}
wordApp=[SBApplication applicationWithBundleIdentifier:@"com.microsoft.Word"];
if ([wordApp isRunning]){
WordDocument *activeWordDoc=[wordApp activeDocument];
WordTextRange *allTextRange=[activeWordDoc textObject];
WordFind *findObj=[allTextRange findObject];

[findObj executeFindFindText:@"FirstText"
matchCase:YES
matchWholeWord:YES
matchWildcards:YES
matchSoundsLike:NO
matchAllWordForms:NO
matchForward:YES
wrapFind:WordE265FindContinue
findFormat:NO
replaceWith:@"SecondText"
replace:WordE273ReplaceAll
];

{code}

Here is the part of gdb output:

-[NSCFBoolean enumCodeValue]: unrecognized selector sent to instance 0xa07e7818
+*(gdb) info symbol 0xa07e7818*+
__kCFBooleanFalse in section LC SEGMENT.__DATA._data of /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
+*(gdb) po 0xa07e7818*+
0

Additionally: here are the enum parts from Word.h
{code}
enum WordE265 {
WordE265FindStop = '\002\231\000\000',
WordE265FindContinue = '\002\231\000\001',
WordE265FindAsk = '\002\231\000\002'
};
typedef enum WordE265 WordE265;

enum WordE273 {
WordE273ReplaceNone = '\002\241\000\000',
WordE273ReplaceOne = '\002\241\000\001',
WordE273ReplaceAll = '\002\241\000\002'
};
typedef enum WordE273 WordE273;
{code}



Now, I guess, it does not like some of the enumerators values.
Any suggestion? How can I debug this error?

P.S. my Ms-Word 2008 is version 12.2.3.

Oct 30, 2010 7:49 PM in response to DavidMan

It seems to be working. I think it might be confused about the result. I just wrapped the whole thing in a try/catch block and it executed without error:

#import <Cocoa/Cocoa.h>
#import "Word.h"
int main(int argc, char * argv[])
{
if(NSApplicationLoad())
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

@try
{
WordApplication * wordApp=[SBApplication applicationWithBundleIdentifier:@"com.microsoft.Word"];

if([wordApp isRunning])
{
WordDocument *activeWordDoc=[wordApp activeDocument];
WordTextRange *allTextRange=[activeWordDoc textObject];
WordFind *findObj=[allTextRange findObject];

[findObj executeFindFindText:@"FirstText"
matchCase:YES
matchWholeWord:YES
matchWildcards:YES
matchSoundsLike:NO
matchAllWordForms:NO
matchForward:YES
wrapFind:WordE265FindContinue
findFormat:NO
replaceWith:@"SecondText"
replace:WordE273ReplaceAll];
}

}
@catch(NSException * e)
{
}
@finally
{
}

[pool drain];
}

return 0;
}


AppleEvents are really nasty underneath. The scripting bridge is new. Combine that with an enormous application like Microsoft Word and this might be as good as it gets.

Message was edited by: etresoft

Oct 30, 2010 8:10 PM in response to etresoft

*It worked here too!*
Thank you very much, I appreciate it!

Though it throws warning in the console:
[NSCFBoolean enumCodeValue]: unrecognized selector sent to instance

But is does not crash because of @try/catch block. I will leave it as it is now.
I will keep in mind for the future that this is a Microsoft product and not everything will be without error; so I will use try/catch 🙂


What I need to do now is to:
1. search for the text
2. if found, analyze it and replace it with the field codes.
3. Field codes, depending on the situation, should show different text.
4. GOTO 1.

I will try to work it out. If I have problems, shall I post the question again ini this topic or shall I close this one, give you your absolutely deserved "Solved" 10 points and open the new topic? Or will it be too much to open separate topic?
I just don't know the etiquette of this forum...

Oct 30, 2010 8:56 PM in response to DavidMan

DavidMan wrote:
I will keep in mind for the future that this is a Microsoft product and not everything will be without error; so I will use try/catch 🙂


I'm not so sure it is Microsoft's fault. Microsoft's recent Mac applications are very good, albeit very complex. Apple's AppleEvents, upon which the ScriptingBridge and AppleScript are based, is ancient, nasty stuff.

What I need to do now is to:
1. search for the text
2. if found, analyze it and replace it with the field codes.
3. Field codes, depending on the situation, should show different text.
4. GOTO 1.

I will try to work it out. If I have problems, shall I post the question again ini this topic or shall I close this one, give you your absolutely deserved "Solved" 10 points and open the new topic? Or will it be too much to open separate topic?
I just don't know the etiquette of this forum...


Once you think your question is resolved, just mark it solved and create new ones. If you feel a little context might be in order, include a link to one or more of your previous threads so people don't rehash old issues.

Unfortunately, it appears that if you have further issues, they might be more suited to Microsoft's own forums: http://www.officeformac.com/productforums/. This question was appropriate here because it was generally about the Scripting Bridge.

Also, we don't know for sure what is causing this exception. It might be a good idea to go ahead and file a bug report on it: http://developer.apple.com/bugreporter/. I think it is an Apple bug rather than a Microsoft bug, so start there.

Apr 1, 2016 6:43 AM in response to DavidMan

Hello All,


I need to create Header file for Microsoft Power Point, Microsoft Excel and Adobe Reader. I have created PowerPoint Header file using


$ sdef /Applications/Microsoft\ Office\ 2011/Microsoft\ PowerPoint.app | sdp -fh --basename MicrosoftPowerPoint


But it is giving me error while building the app.


MicrosoftPowerPoint.h:3028:2: Redefinition of enumerator 'MicrosoftPowerPoint4006ShapeRange'

Any one please help me, After creating Header file does it requires to add any script or settings in the app. I need to integrate this module in the same mac app in which i have integrated "MicroSoftWord.h".


Thanks in advance.

Microsoft Word API for Mac OS: Is it possible using Objective-C?

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.