如何以编程方式保护 Word 文档免受用户窗体命令按钮的影响?
How do I programmatically protect a Word Document from a UserForm CommandButton?
我有一个 MS Word 文档,它是一个 10 个问题的评估,由顶部的 table 组成,包含详细信息,例如您的姓名和下面的 table 部分,每个部分用于 1 个问题和答案以及所需的书签。该文件的基本要点是;
- 打开时,文档 'hides' 并显示
UserForm
以完成所需的问题,包括您的姓名(如以下示例代码所示)。
UserForm
是 'locked',关闭它的唯一方法是强制关闭 MS Word 或单击命令按钮并输入正确的密码。
- 表单的导航是通过 'next' 和 'previous' 命令按钮实现的。
- 表单末尾有一个 'Submit' 按钮(代码如下所示),单击该按钮时,系统会提示用户确认他们已准备好提交评估,如果 'Yes' 表单将
UserForm
控件的值写入文档中的相关书签,用封闭书签替换一些书签,保存文档,撰写电子邮件并附加准备发送的文档,然后调整 window 并关闭 MS Word。
简而言之,上面的方法非常有效,但是在测试之后,一些用户设法将他们的一些答案加倍。
由于用户分布在全国各地,可能很难取得联系(而且对于某些用户来说,很难弄清楚事情是如何发生的)所以我得出的结论最合乎逻辑的原因是:
- 用户尚未 'enabled content' 完成文档,然后才 'enable content' 并被迫通过
UserForm
完成评估,因此在提交时添加另一个答案书签位置。
因此,为了克服这个问题,我加入了保护文档免遭编辑的代码。
它在各种代码块中按预期保护和取消保护,例如管理员用于关闭用户窗体的覆盖,通常用于标记和文档打开时(当然启用宏)或用户窗体终止时。 但是 在提交时保存文档之前保护文档的行似乎不起作用(因为没有更好的术语)。
最好在所有情况下打开文档时都对其进行保护。由于文档是在启用保护的情况下分发的,起初它可以正常工作,但是在提交后可以打开和编辑保存的版本,如果没有启用宏(如果出现提示)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
我有一个 MS Word 文档,它是一个 10 个问题的评估,由顶部的 table 组成,包含详细信息,例如您的姓名和下面的 table 部分,每个部分用于 1 个问题和答案以及所需的书签。该文件的基本要点是;
- 打开时,文档 'hides' 并显示
UserForm
以完成所需的问题,包括您的姓名(如以下示例代码所示)。 UserForm
是 'locked',关闭它的唯一方法是强制关闭 MS Word 或单击命令按钮并输入正确的密码。- 表单的导航是通过 'next' 和 'previous' 命令按钮实现的。
- 表单末尾有一个 'Submit' 按钮(代码如下所示),单击该按钮时,系统会提示用户确认他们已准备好提交评估,如果 'Yes' 表单将
UserForm
控件的值写入文档中的相关书签,用封闭书签替换一些书签,保存文档,撰写电子邮件并附加准备发送的文档,然后调整 window 并关闭 MS Word。
简而言之,上面的方法非常有效,但是在测试之后,一些用户设法将他们的一些答案加倍。
由于用户分布在全国各地,可能很难取得联系(而且对于某些用户来说,很难弄清楚事情是如何发生的)所以我得出的结论最合乎逻辑的原因是:
- 用户尚未 'enabled content' 完成文档,然后才 'enable content' 并被迫通过
UserForm
完成评估,因此在提交时添加另一个答案书签位置。
因此,为了克服这个问题,我加入了保护文档免遭编辑的代码。
它在各种代码块中按预期保护和取消保护,例如管理员用于关闭用户窗体的覆盖,通常用于标记和文档打开时(当然启用宏)或用户窗体终止时。 但是 在提交时保存文档之前保护文档的行似乎不起作用(因为没有更好的术语)。
最好在所有情况下打开文档时都对其进行保护。由于文档是在启用保护的情况下分发的,起初它可以正常工作,但是在提交后可以打开和编辑保存的版本,如果没有启用宏(如果出现提示)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