How Programatically Close All Open Word Docs? RRS feed

  • Question

  • A novice at automating MS Office, I'm programming Word from Visual FoxPro, and have run into the problem that if a user tries to open a document that's already open, nothing appears to happen since it encounters a "File in use" error, which the user can't see since it opens behind another window. In this particular application it would be satisfactory simply to close any open documents each time an attempt is made from the menu to open another document regardless of whether there's a conflict. And that's better anyway since otherwise users will be confused.

    Here is my initial test of the method I thought might accomplish that:

    oWord = GETOBJECT(, "Word.Application")
    ? oWord.Documents.Count
    FOR i=1 TO oWord.Documents.Count
       ? oWord.Documents(i).Name

    And that worked, at first, although oWord.Documents.Count was always = 1 since the already opened documents belonged to separate instances of Word, being opened by the code below. But at least I was able to run the above code again and again to close each remaining document one at a time, so the method seemed promising.

       oWord = CREATEOBJECT( "Word.Application" )
       oWord.Visible = .T.
       FULLPATH=ACDBF + 'Correspondence\' + ARC_LETRS(I)
       sDoc = FULLPATH      
       oWord.Documents.Open( sDoc, 0, 0 ) && parm 3 read only = not
       RELEASE oWord

    To improve the situation, I re-wrote the code just above to open all the previously opened docs in the same Word instance, but then the little program for closing them stopped working, reporting oWord.Documents.Count as 0 each time I tried it. And that happened even when I put back the code just above.

    So now I'm mystified.

    Am I going about this the wrong way anyway?

    Thanks in advance for your help.


    • Edited by Petun Tahd Thursday, October 31, 2013 9:49 PM
    Thursday, October 31, 2013 9:37 PM


All replies

  • Hi Petun,

    Because you will new an application to open a document, I think you could close all of the applicaiton before opening.

    I'm familiar with VBA but no Visual ForPro, so I could only give a VBA macro for your reference.

    Hope it can help you.

    Public Sub Test()
    'Requires reference to Word object library
    Dim oWord As Object
    Set oWord = GetObject(Class:="Word.Application")
    If Not oWord Is Nothing Then
        oWord.Quit False
        Set oWord = Nothing
    End If
    Loop Until oWord Is Nothing
    End Sub

    Another VBA link for your reference:

    Close/Release Word object in VBA?

    Friday, November 1, 2013 1:42 PM
  • Certainly it's simpler just to quit Word than to close each document individually, so thanks for that idea, but unfortunately it doesn't solve my problem. Based on textbooks by the experts, the Visual FoxPro way of getting a reference to Word is the one I'm using, oWord = GetObject( , "Word.Application" ). [To explain the 'empty' initial comma: unfortunately, VFP can't pass named parameters, so you have to provide empty commas for every irrelevant parm the method is expecting until you reach the one you want, and the first parm expected by GetObject() is the file name, which is not known in this case.]

    This GetObject call does work in the sense that it returns a reference to Word. If I omit it and go straight to the ? oWord.Documents.Count statement (where '?' here means 'print to the screen'), I get an error.

    But if I keep the GetObject call, and get a reference to Word, it thinks there are no documents open, so ? oWord.Documents.Count prints as zero. Both Microsoft's documentation and a book by a VFP expert, GetObject() will return an error if no instance of the requested application exists; so this use of GetObject() must be getting the one the does exist, and contains the documents to be closed. So it is a mystery why it thinks none are open.

    If this odd behavior were not puzzling enough, it's particularly puzzling that the first time I tried to code I list above, it worked, and did close each document, though just one at a time since I had opened then in separate instances...


    • Edited by Petun Tahd Saturday, November 2, 2013 5:26 PM
    Saturday, November 2, 2013 2:43 PM
  • Progress, but not there yet:

    I have found that the following code (starting below the '=====' line below) partly does the job. However, there are two problems:(1) It requires two iterations of oWord.Quit to get rid of a single instance of Word: i.e., the WAIT command 'Quitting one Word application' occurs twice before the Word instance gets closed (disappears from the task bar); (2) When multiple instances of Word exist, as they do in this case since the code I used to establish them (presented above in my initial post) instantiates one for each document, then the above code must be run separately for each one.

    Or maybe the second problem is a bug in the way I wrote this?


    LOCAL oWord
    AssumeOpen = .T.
    DO WHILE AssumeOpen
       oWord = GETOBJECT( , "Word.Application")
       IF AssumeOpen
          WAIT 'Quitting one Word application'

    ? 'Okay, any open Word has been closed'

       WAIT 'Set AssumeOpen to .F.'


    • Edited by Petun Tahd Saturday, November 2, 2013 9:42 PM
    Saturday, November 2, 2013 6:44 PM
  • Hi Peyton

    I believe this article explains why this is happening

    In the .NET world, it's possible to work with processes, which makes it simpler to get to these things. Not sure if/how you can do that with VFP - it would certainly involve the Windows API...

    Cindy Meister, VSTO/Word MVP, my blog

    Tuesday, November 5, 2013 5:46 PM
  • My impression is that the code shown in the KB article you cite is beyond my level of competence to implement, unless there's a simple way just to compile it and run it in complete ignorance of how it works.

    It also depends on how easily my client can live with the current situation, requiring users to remember to close open documents vs. paying me or a more NET-savvy programmer to implement the solution you suggest.

    For now, therefore, I'll simply say 'thank you' and mark your post as the answer.


    • Marked as answer by Petun Tahd Tuesday, November 12, 2013 2:15 PM
    • Unmarked as answer by Petun Tahd Tuesday, November 12, 2013 2:15 PM
    Tuesday, November 12, 2013 2:15 PM
  • Hi Peyton

    If you find you need to implement something like this, your first stop should be a VFP forum where you can ask whether VFP natively has functionality that can work with Processes, or whether someone has Windows API code written for VFP that does this.

    Theoretically, you wouldn't need the .NET Framework since all it does is expose this Windows API functionality to the .NET programmer. The big question is, how can you do the same in VFP. And as this is not a VFP forum, no one here can tell you that...

    Cindy Meister, VSTO/Word MVP, my blog

    Tuesday, November 12, 2013 2:43 PM