Search code examples
vbams-worduserform

How do I programmatically protect a Word Document from a UserForm CommandButton?


I have a MS Word document which is a 10 question assessment made up of a table at the top containing details such as your name and table sections below, each for 1 question and answer and as required bookmarks. The basic gist of the document is;

  1. On open, the document 'hides' and displays a UserForm to complete the required questions, including your name (Which is shown in the below sample code).
  2. The UserForm is 'locked' where the only way to close it is to force close MS Word OR to click a command button and enter the correct password.
  3. Navigation of the form is achieved with 'next' and 'previous' command buttons.
  4. At the end of the form is a 'Submit' button (code shown below) which when clicked the user is prompted to confirm they are ready to submit the assessment, and if 'Yes' the form writes the values from the UserForm controls to a relevant bookmark in the document, replaces some of the bookmarks with enclosing bookmarks, saves the document, composes an email and attaches the document ready for sending, then resizes the window and closes MS Word.

In short, the above works perfectly, however after testing some users managed to double up some of their answers.

As the users are in various locations around the country, it can be difficult to get in touch (and trying to work out how things happened can be difficult with some users) so I've come to the conclusion the most logical reason would be:

  • The User has not 'enabled content' and have completed the document only to then 'enable content' and be forced to complete the assessment via the UserForm, thus on submission adding another answer to the bookmark locations.

So to overcome this I've included the code to Protect the Document from editing.

It protects and unprotects as intended in various blocks of code for example the override used by admins to close the userform, generally for marking and when the document opens (with macros enabled of course) or when the Userform terminates. However the line to Protect the Document before it saves on submission does not seem to work (for lack of a better term).

It's preferred that the document is protected when it's opened in all instances. As the document is distributed with protection enabled, at first it works perfectly however after submission the saved version can be opened and edited without the UserForm if macros are not enabled (if prompted).

This code is a shortened version (omitting 19 variables, 15 Bookmark references and 4 enclosing bookmark replacements). We'll Assume for the example that to protect/unprotect the sheet, the password is "abc123".

Private Sub cmdSubmit_Click()

Dim confirm As Integer

confirm = MsgBox("Have you checked all your answers are correct?" & vbNewLine & vbNewLine & "By clicking 'Yes' you are confirming your completion of this Assessment", vbYesNo, "Submission Confirmation")

        If confirm = vbNo Then
            Exit Sub
        ElseIf confirm = vbYes Then
            MsgBox "A new email will open with this document attached." & vbNewLine & vbNewLine & "Please click send and set the security status to 'Un-classified'", vbInformation, "For Your Information"

Dim yourName As String

    yourName = UserForm1.TextBox1.Text

    If Not ActiveDocument.ProtectionType = wdAllowOnlyReading Then
        ActiveDocument.Protect wdAllowOnlyReading, , "abc123"
    End If

    ActiveDocument.Unprotect "abc123"

        ActiveDocument.Bookmarks("name").Select
            With Selection
            .TypeText Text:=yourName
            End With

        ActiveDocument.Bookmarks("name").Select
            With Selection
            .MoveEnd Unit:=wdLine, Count:=1
            .Bookmarks.Add name:="name"
            End With

End If

    ActiveDocument.Protect wdAllowOnlyReading, , "abc123"

    ActiveDocument.SaveAs2 FileName:="H:\Assessment 1_" & yourName, FileFormat:= _
        wdFormatXMLDocumentMacroEnabled, LockComments:=False, password:="", _
        AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
        EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, SaveFormsData _
        :=False, SaveAsAOCELetter:=False, CompatibilityMode:=14

'Some code executes here to attach the saved document to a new outlook mailitem ready for sending. 

    Application.WindowState = wdWindowStateNormal
    Application.Resize 600, 700
    Application.Quit

End Sub

I've stepped through the code and the line is executed. To my understanding the whole code is in logical order and I don't see any reason it wouldn't either protect the document or when re-opened, open with protection enabled as it's been saved after protection has been set.

I have a feeling it's either something I haven't yet learned in Word VBA or something regarding the SaveAs code is not saving the protection, any thoughts?


Solution

  • You're applying full read-only protection. But when you SaveAs you're changing the document name and the document type, from not macro-capable to macro-capable. This nullifies the "read-only" status. So you need to protect again after saving, then do a "plain" save.

    If you were to implement protecting for forms instead of "read-only" you could avoid this. Since you're not setting any editable areas in the document, for either protection type, it wouldn't make any difference that I can see which you use...

    doc.Protect wdAllowOnlyFormFields, True, "abc123"
    

    Below is my test code, with optimizations to what you posted. One important change I made is to check the protection type before issueing the Unprotect command (if at all), a problem you were having, originally. I use a Document object, rather than repeating ActiveDocument because it is possible the user could change documents, somehow. And I use objects instead of Selection for the bookmarks.

    Public Sub cmdSubmit_Click()
    
        Dim confirm As Integer
        Dim yourName As String
        Dim doc As Word.Document
        Dim rngBookmark As Word.Range
    
        Set doc = ActiveDocument
        confirm = MsgBox("Have you checked all your answers are correct?" & vbNewLine & _
                  vbNewLine & "By clicking 'Yes' you are confirming your completion of this Assessment", _
                  vbYesNo, "Submission Confirmation")
    
        If confirm = vbNo Then
            Exit Sub
        ElseIf confirm = vbYes Then
            MsgBox "A new email will open with this document attached." & vbNewLine & _
                   vbNewLine & "Please click send and set the security status to 'Un-classified'", _
                   vbInformation, "For Your Information"
            yourName = UserForm1.TextBox1.Text
    
            If doc.ProtectionType <> wdNoProtection Then
                doc.Unprotect "abc123"
            End If
            Set rngBookmark = doc.Bookmarks("name").Range
            rngBookmark.Text = yourName
            doc.Bookmarks.Add Name:="name", Range:=rngBookmark
    
        End If
    
        doc.Protect wdAllowOnlyReading, , "abc123"
    
        doc.SaveAs2 fileName:="c:\Test\Assessment 1_" & yourName, FileFormat:= _
            wdFormatXMLDocumentMacroEnabled, LockComments:=False, Password:="", _
            AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
            EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, SaveFormsData _
            :=False, SaveAsAOCELetter:=False, CompatibilityMode:=14
    
        'Saving to a different name, in a different file type, annuls the read-only protection
        'so protect again
        doc.Protect wdAllowOnlyReading, , "abc123"
    
    'Some code executes here to attach the saved document to a new outlook mailitem ready for sending.
    
        Application.WindowState = wdWindowStateNormal
        Application.Resize 600, 700
        Application.Quit
    End Sub