Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VERY SIMPLE use of MS WORD Spell checker 1

Status
Not open for further replies.

JohnWMAC

Programmer
Aug 22, 2018
9
US
I found what I thought was the perfect solution to spellchecking individual words using automation of MS WORD from VFP9 (SP2). When I started using it, it worked PERFECTLY, then, all of a sudden, it quit. "QUIT" meaning WORD was always returning a TRUE condition even when the word in question was obviously misspelled. Details follow:

WORD - MS Office 365
VFP9 (SP2)
Windows 10

This code is in the INIT procedure of my Form:

PUBLIC oWord
oWord=CREATEOBJECT("Word.Application")
(WORD always fires up perfectly)

Then I have a TEXTBOX on the form in which the following code appears in the LostFocus event:

lCorrect = .F.
Store "JNHYGT" to answer
lCorrect = oWord.CheckSpelling(answer)

set step on

IF lCorrect
(I ALWAYS land here)
ELSE
MESSAGEBOX(ALLTRIM(answer) + " is NOT a valid word",0)
ENDIF

lCorrect ALWAYS comes back as TRUE.

Now it gets interesting - When I run this in Debug mode and STOP the execution where indicated, and then go to the COMMAND window and call WORD's spellchecker with the same "JNHYGT", it comes back false!!
I reinstalled VFP9 which did nothing. As I said, when I first wrote this code, it worked PERFECTLY and then all of a sudden, it started to fail. I assume you may think it is an environmental issue on my computer which is a reasonable assumption so I am looking for trouble shooting suggestions rather than a simple solution.
 
Mike,

The problem with your approach is it's dependency on Word's UI. This can be problematic for applications that want to fully integrate spell-checking. While my approach is much more complex, it is fully integrated.

Sometimes, we have to go the extra mile. Sometimes, we need to enhance our skills. And all these "Great Post" marks on this forum is BS.
 
Because it reminds me of Facebook's ThumbsUp - and I can't stand FaceBook...
 
Vernspace,

The point of Tek Tips' "Great post" feature is that it alerts forum members to problems that have either been resolved or which have attracted helpful replies. When someone browses the list of threads - perhaps to look for threads similar to their own problems, or simply to find questions they might be able to answer - the presence of a red start can point them in the right direction. Similarly, if you are browsing within a thread, the red stars can tell you at a glance which replies have helped to solve the problem.

I would agree that the system is sometimes mis-used and doesn't always achieve its aims. But to condemn it simply because it reminds you of a feature you dislike in Facebook seems a little over the top.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike Lewis said:
The point of Tek Tips' "Great post" feature is that it alerts forum members to problems that have either been resolved or which have attracted helpful replies.

With the recent shenanigans, I am sure the 'Great Post' system has been used (abused?) to support the content of the person posting rather than the problem has been resolved. I am guilty of this action.



Regards,

David

Recreational Developer and End User of VFP for my personal use in 'Amateur Radio' and 'British Railways' related Applications.
 
Thank you JohnWMac and Mike Lewis. You have encouraged me to include spell checking at various points in an application.
I have gone for Mike’s approach of using Microsoft Word, and the slightly modified code for my cmdSpellcheck.click() is :

Code:
LOCAL loWord, loDoc, llWasVisible
 
loWord = CREATEOBJECT("Word.Application")
IF !(TYPE("loword") = "O")
   MESSAGEBOX("Cannot perform the spell check." + CHR(10) + CHR(10) + ;
   "Unable to open Microsoft Word", 48)
   RETURN
   ENDIF 		

* Go ahead and do the spell check 
WITH loWord
   loDoc = .Documents.add        && Open a new doc within Word
	
   * Copy the text to the new doc
   loDoc.Range(0,0).InsertAfter(thisform.frmcust.page2.edtnotes.Value)
   
   * Make it visible
   llWasVisible = .visible		&& save the visible state
   .visible = .T.
   .WindowState = 0			&& normal window
   .Activate
   loDoc.CheckSpelling     && Call the spell checker

   * Copy the text back 
   thisform.frmcust.page2.edtNotes.Value = loDoc.content.text
   loDoc.close(0)          && Close the Word doc (without prompting)

   * Minimise Word (otherwise it might still be on top at this point)
   .WindowState = 2	
	
   IF NOT llWasVisible
		.visible = .F.
   ENDIF 

   MESSAGEBOX("Spellcheck completed", gcShortTitle)
   ENDWITH


This does indeed invoke the (Office 365) word spell checker, and a task is created with a flashing W showing in the Windows TaskBar. But the original application – particularly if it is running full-screen - is still the only one showing on the screen.

What code should I include to make the Word application - which is telling me interesting thing about the text I am validating - come to the forefront until I send it away and revert to my own application?
 
AndrewMozley I believe all you need to do is turn on the "visible" property which Mike's code actually does. Again, in my case, where I just want to spellcheck a single word, I want WORD to be as quiet as possible. BTW, and I didn't say this previously, my interest in spellchecking is because I am writing a program to simulate the game WORDLE ([URL unfurl="true"]https://www.nytimes.com/games/wordle/index.html[/url]) which is posted daily in the New York Times. (Yes this is a trivial project and it is just to entertain myself, but it's better than watching TV). The advantage of my program is that you can play all day long given the ability for another person to enter a word after which you take over and try to resolve the puzzle. Obviously, the spellchecker prohibits both the target word and any of your guesses from being non-words.
 
Andrew,

I'm pleased that you found my code useful. I see that you have modified it to make it more self-contained, which is good.

My version uses a separate method to open Word. This goes beyond a simple CREATEOBJECT(), in that it: (i) it only needs to launch Word once (within a given form); and (ii) if Word is already instantiated, it uses the existing object reference. However, none of this is essential; I'm not suggesting you should change your version.

I should also have mentioned that my version relies on the presence of a custom property, oWord, to store the object reference.

If anyone is interested, here is my code for instantiating Word:

Code:
* Try to instantiate Word. If successful, return .T. 

LOCAL loWord, llError, llJunk

IF NOT ISNULL(thisform.oWord)
	* Word has been instantiated ...
	TRY
		llJunk = thisform.oWord.Visible
	CATCH
		* ... but an attempt to access its PEMs has failed;
		* this indicates that the user closed Word interactively
		* since it was last instantiated; the solution is to
		* clear out the object reference so that we can instantiate
		* it again.
		thisform.oWord = NULL
	ENDTRY
ENDIF 
	
IF ISNULL(thisform.oWord)
	* Word not yet instantiated (in this form). So first try to get
	* a reference to an existing Word session
	
	TRY
		llError = .f.
		loWord = GETOBJECT(,"word.application")
	CATCH
		llError = .t.
	ENDTRY
	
	IF llError
		* That didn't work, so try for a reference to an existing Word session
		TRY
			llError = .f.
			loWord = CREATEOBJECT("word.application")
		CATCH
			llError = .t.
		ENDTRY
		
		IF llError
			* That didn't work either, so jump out
			RETURN .F.
		ENDIF 
		
	ENDIF 

	* Successfully opened Word. Store the object ref.
	thisform.oWord = loWord
	
	RETURN .t.
	
ENDIF

You would store this in a method of the form (and create the custom oWord property for the same form).

By the way, the above code is not specific to spell checking. It simply instantiates Word, which you can then use for whatever you want.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thank you John. The Word window certainly can be visible, showing possible spelling corrections. But if my application is running full screen, and is in the foreground, then the Word window cannot be seen.

I would like to bring the Word screen to the foreground, so that it is visible (until the user sends it away).

Is there a VFP instruction which I can put into my application to make this happen?
 
John,

You say you are using the single-word version of Word's spell checker to write a Wordle program. Could I suggest a better approach.

Rather than relying on Microsoft's dictionary, which might contain all kinds of entries that might not be Wordle-compliant (personal names, acronyms, etc), you can download your own word list and customise it to your needs.

I have recently been using a 194,000-word dictionary, which I downloaded from In fact, I found that this contained too many highly obscure words for my needs, so I switched to a smaller 65,000-word version, which I got from the same site.

Once you have downloaded the dictionary (which is a simple text file), you can create a sub-set containing only the five-letter words. You could import this into a DBF, then index it and search it with SEEK or LOCATE or whatever. You would then have a very much simpler and faster method of verifying a word, without the overhead of calling Microsoft Word.

And once you have your own dictionary, the door is open to creating all kinds of word games and puzzles. I have been using it to create a Trackword puzzle, a palindrome generator and an anagram solver. If you are interested, look over some of the recent threads in the Puzzles for Programmers forum, starting with thread1551-1811770.

Good luck with the project. As you say, it's better than watching television.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Windows has a (little-documented) built-in spelling interface, does not need Word ...

Unfortunately it isn't pure ActiveX, and requires use of a tlb and robust early binding (Createobject can't be used). Foxpro isn't my area of expertise, so don't know if it can work there - but it is relatively easy in VBA/VB6. I'd be happy to provide my demo VB6 code if there is anyone with the expertise necessary to translate it to FoxPro
 
Strongm,

that would be nice, I don't see the need to translate this into VFP, as VB can make it a COM control and we could use that in VFP.
Or is it VB.NET? Then there's the Interop Forms Toolkit,, which aimed at VB6 developers to help migrating to .NET but also is usable for interop with VFP.


Chriss
 
Mike Lewis
Thank you Mike for your information on another way to deal with spellchecking. I will play with this and provide feedback. I am not enamored with the call to WORD and although it works for me since I have MS Office installed, how about providing a copy of the program to a friend/customer who may not have OFFICE...I'm pretty sure that's part of what you were suggesting with your "Foxpro-only" solution.
 
Mike Lewis said:
a 194,000-word dictionary, which I downloaded from

Mike,

I used that dictionary in creating a VFP app to help me with difficult (for me anyway) crossword puzzles. For example if I'm looking for a six-letter word with first and third letters W & G, I type "W,G,,," in the textbox and the returns are listed.

You are right about the dictionary containing unrecognizable words.

Steve
 
>Or is it VB.NET

No, it is classic VB6.

But it is only a basic demonstration of the technique, not in any shape to be turned into a robust COM control (and I'm afraid I don't have the urge to do that myself currently ...).



 
Steve,

Good to hear that I am not the only VFP person who uses that dictionary, and I like the idea of your crossword solver. You probably know that there are dozens of Androiod and iPhone apps that do the same thing (I use one called Crossword King), but it is much more satisfying to write your own.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Andrew,

I'll try to answer your question about how to bring Word to the foreground.

When I run your code as it stands, I see Word appearing on the taskbar, but it is behind VFP's own window, which is not what you want. So I put [tt]_screen.WindowState= 1[/tt] just before [tt]loDoc.CheckSpelling[/tt]. So now the VFP program is minimised and Word becomes visible. That seems to have solved the problem, but I don't really understand why it was happening. I don't rmember it being an issue before.

I also put [tt]_screen.WindowState= 2[/tt] to bring the VFP window back to maximised once the spell check is finished.

I noticed a couple of other points about your (our) code:

- The messagebox at the end has as its second parameter something called [tt]gcShortTitle[/tt]. This is something that is specific to my applications (and which you are probably using as well), so it should be removed to prevent an error.

- In fact, I would argue that the messagebox shouldn't be there at all. It should be obvious to the user that the spell check has finished. But I can see that you would probably find it useful when testing the program.

- It is important to close Word when you have finished the spell check, otherwise a new instance will be loaded every time you run it. So add [tt].Quit[/tt] towards the end of the WITH / ENDWITH loop.

In my own version, I handled the closing of Word in the form's Destroy, as follows:

Code:
* Close the Word session that was used for spell checking (if any)
IF NOT ISNULL(thisform.oWord)
  * We did open Word in this form
   IF thisform.oWord.documents.count = 0
      * and there are no other documents open
      thisform.oWord.quit
  ENDIF
ENDIF

As you can see, this will only close Word if it was opened in the form itself (rather than by another form or another application or by the user interactively), and only if no other documents are open. But you don't really need to do this in your version, as you are opening and closing Word each time you run the spell check.

I hope this all makes sense.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
For those interested in getting a list of spelling suggestions for a misspelled word without resorting to using Word's UI. Note: you will need to modify as this returns XML required for our contextmenu control.

Code:
LPARAMETERS tcSuggestedWordsXML AS String
LOCAL lcWord, lcWordKey, lcSuggestedWord, lcSuggestedWordXML, lcSuggestedWordsXML, loWord

STORE "" TO lcSuggestedWordXML, lcSuggestedWordsXML

lcWord = This.CallingObject.SelText
loWord = CREATEOBJECT("Word.Application")
loWord.Documents.Add
DOEVENTS

IF NOT loWord.CheckSpelling(lcWord)
   FOR i = 1 TO loWord.GetSpellingSuggestions(lcWord).Count
       lcWordKey = "WORD" + TRANSFORM(i)
       lcSuggestedWord = loWord.GetSpellingSuggestions(lcWord).Item(i).Name

TEXT TO lcSuggestedWordXML TEXTMERGE NOSHOW
    <MenuItem text="<<lcSuggestedWord>>" itemtype="256" itemstate="0" key="<<lcWordKey>>" tag=""/>
ENDTEXT

       lcSuggestedWordsXML = IIF(EMPTY(lcSuggestedWordsXML), lcSuggestedWordXML, lcSuggestedWordsXML + CRLF + lcSuggestedWordXML)

   ENDFOR
ELSE
   lcSuggestedWordsXML = "NOPROCESS"
ENDIF

loWord.Quit
RELEASE loWord
DOEVENTS

tcSuggestedWordsXML = lcSuggestedWordsXML
 
And here is how you can add a word to Word's custom dictionary:

Code:
LOCAL lcWord, loWord, liBytes

lcWord = This.CallingObject.SelText
loWord = CREATEOBJECT("Word.Application")
liBytes = AddToCustomDictionary(loWord, lcWord)

loWord.Quit
RELEASE loWord
DOEVENTS

*!*    Quality check
*!*    To be used with RTF spell-checker
FUNCTION AddToCustomDictionary(toWord AS Object, tcWord AS String) AS Integer
   LOCAL lcCustomDictionaryPath, lcWord, lcWordString, loCustomDictionary, liBytes

   loCustomDictionary = toWord.CustomDictionaries.ActiveCustomDictionary
   lcCustomDictionaryPath = ADDBS(loCustomDictionary.Path) + loCustomDictionary.Name

   IF NOT FILE(lcCustomDictionaryPath, 2)
      RETURN -1
   ENDIF

   lcWord = STRCONV(tcWord, 5)
   lcWordString = FILETOSTR(lcCustomDictionaryPath)
   
   IF lcWord $ lcWordString
      RETURN 0
   ENDIF

   lcWord = lcWord + CHR(13) + CHR(0) + CHR(10) + CHR(0)
   liBytes = STRTOFILE(lcWord, lcCustomDictionaryPath, 1)

   RETURN liBytes

ENDFUNC

Just about ANYTHING can be done in VFP.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top