如何以编程方式保护 Word 文档免受用户窗体命令按钮的影响?

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

我有一个 MS Word 文档,它是一个 10 个问题的评估,由顶部的 table 组成,包含详细信息,例如您的姓名和下面的 table 部分,每个部分用于 1 个问题和答案以及所需的书签。该文件的基本要点是;

  1. 打开时,文档 'hides' 并显示 UserForm 以完成所需的问题,包括您的姓名(如以下示例代码所示)。
  2. UserForm 是 'locked',关闭它的唯一方法是强制关闭 MS Word 或单击命令按钮并输入正确的密码。
  3. 表单的导航是通过 'next' 和 'previous' 命令按钮实现的。
  4. 表单末尾有一个 'Submit' 按钮(代码如下所示),单击该按钮时,系统会提示用户确认他们已准备好提交评估,如果 'Yes' 表单将 UserForm 控件的值写入文档中的相关书签,用封闭书签替换一些书签,保存文档,撰写电子邮件并附加准备发送的文档,然后调整 window 并关闭 MS Word。

简而言之,上面的方法非常有效,但是在测试之后,一些用户设法将他们的一些答案加倍。

由于用户分布在全国各地,可能很难取得联系(而且对于某些用户来说,很难弄清楚事情是如何发生的)所以我得出的结论最合乎逻辑的原因是:

因此,为了克服这个问题,我加入了保护文档免遭编辑的代码。

它在各种代码块中按预期保护和取消保护,例如管理员用于关闭用户窗体的覆盖,通常用于标记和文档打开时(当然启用宏)或用户窗体终止时。 但是 在提交时保存文档之前保护文档的行似乎不起作用(因为没有更好的术语)。

最好在所有情况下打开文档时都对其进行保护。由于文档是在启用保护的情况下分发的,起初它可以正常工作,但是在提交后可以打开和编辑保存的版本,如果没有启用宏(如果出现提示)UserForm

此代码是一个简化版本(省略了 19 个变量、15 个书签引用和 4 个封闭的书签替换)。例如,我们假设 protect/unprotect 和 sheet 的密码是 "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

我单步执行了代码并执行了该行。据我了解,整个代码是按逻辑顺序排列的,我看不出有任何理由它既不会保护文档,也不会在重新打开时打开并启用保护,因为它是在设置保护后保存的。

我感觉是我还没有在 Word 中学到的东西 VBA 或者关于 SaveAs 代码的东西没有保存保护,有什么想法吗?

您正在应用完全只读保护。但是,当您另存为时,您正在更改文档名称 文档类型,从不支持宏到支持宏。这会使 "read-only" 状态无效。所以保存后需要再次保护,然后"plain"保存

如果您要实施表单保护而不是 "read-only",您可以避免这种情况。由于您没有在文档中设置任何可编辑区域,对于任何一种保护类型,我可以看到您使用哪种保护类型都没有任何区别...

doc.Protect wdAllowOnlyFormFields, True, "abc123"

以下是我的测试代码,对您发布的内容进行了优化。我所做的一个重要更改是在发出 Unprotect 命令(如果有的话)之前检查保护类型,这是您最初遇到的问题。我使用 Document 对象,而不是重复 ActiveDocument,因为用户可能会以某种方式更改文档。我使用对象而不是 Selection 作为书签。

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