如果文件被锁定,如何捕获 wdDialogFileSaveAs 的静默失败?

How to catch silent failure of wdDialogFileSaveAs if file is locked?

我创建了一个包含三个按钮的对话框,其中第三个按钮应将 Word 文档(Office Pro Plus 2013,顺便说一句)保存为 PDF 文件。

Private Sub Button_Dokument_mit_Grafik_als_PDF_speichern_Click()
    Dim Grafik As Boolean
    Grafik = Options.PrintDrawingObjects
    Options.PrintDrawingObjects = True
    With Dialogs(wdDialogFileSaveAs)
        .Format = wdFormatPDF
        ' .Format = 17 '17 = PDF
        .Show
    End With
    Options.PrintDrawingObjects = Grafik
End Sub

如果 PDF 存在,我可以选择覆盖它,这在大多数情况下都有效。

如果要覆盖的 PDF 已经打开,例如在 Adob​​e Reader 中,则文件不会保存,因为它已被锁定。我没有收到任何文件已锁定的通知。

我怎样才能捕捉到这一点并弹出与我在 Word 中手动保存时收到的相同消息?

编辑:
解释为什么我的问题与其他已回答的问题不同:
我不需要检查文件是否已经在 Word 中打开。我将文件保存为 PDF 而不是 Word 文件。
我需要检查文件是否在任何其他应用程序中打开和锁定,例如 Adobe ReaderEdge 或其他应用程序。

此检查已由 Word (and/or OS?) 完成,THIS 是我需要捕获的事件。我完全不明白为什么我需要捕获它,因为检查文件是否存在的结果确实出现了,但是检查文件是否被锁定的结果似乎被忽略了。

VBA 代码的行为就像文件已保存一样,但如果被 Word 以外的任何应用程序锁定,则不会。

我不知道我需要从 Detect whether Excel workbook is already open

中获取哪个代码片段

您可能正在寻找以下内容:

Sub SaveAsPdf()
    Dim Grafik As Boolean
    Grafik = Options.PrintDrawingObjects
    Options.PrintDrawingObjects = True

    Dim fDialog As FileDialog
    Set fDialog = Application.FileDialog(msoFileDialogSaveAs)

    fDialog.Title = "Save a file"
    'works only in Word2016 not in word 2013; 
    'fDialog.InitialFileName = "*.pdf"
    'we can use the filterindex property instead
    fDialog.FilterIndex = 7

    If fDialog.Show = -1 Then
        Dim selectedFilePath As String
        selectedFilePath = fDialog.SelectedItems(1)
        If IsFileInUse(selectedFilePath) Then
            MsgBox "The target pdf file you are trying to save is locked or used by other application." & vbCrLf & _
            "Please close the pdf file and try again.", vbExclamation
        Else
            ActiveDocument.SaveAs2 selectedFilePath, wdFormatPDF
        End If
    End If

    Options.PrintDrawingObjects = Grafik
End Sub

Private Function IsFileInUse(ByVal filePath As String) As Boolean
    On Error Resume Next
    Open filePath For Binary Access Read Lock Read As #1
    Close #1
    IsFileInUse = IIf(Err.Number > 0, True, False)
    On Error GoTo 0
End Function

如果您想使用 wdDialogFileSaveAs 对话框,可以尝试以下代码:

Display 方法将显示对话框而不执行实际功能。您可以验证显示结果以识别单击的按钮并使用 execute 方法执行实际功能。

'Save As Pdf using wdDialogFileSaveAs dialog
'However, it doesn't work as expected.
'The Display method should
Sub SaveAsPdf()
    Dim dlg As Dialog
    Dim dlgResult As Long
    Set dlg = Dialogs(wdDialogFileSaveAs)
    With dlg
        .Format = wdFormatPDF
        dlgResult = .Display
        If dlgResult = -1 Then 'user clicks save button;
            If .Name <> "" Then
                If IsFileInUse(.Name) Then
                    MsgBox "The target pdf file you are trying to save is locked or used by other application." & vbCrLf & _
"Please close the pdf file and try again.", vbExclamation
                Else
                    .Execute
                End If
            End If
        End If
    End With
End Sub

请注意,至少在我的本地环境中,以上代码(wdDialogFileSaveAs 对话框)在 Word 2016 中无法按预期工作。单击保存按钮后,Display 方法将执行实际功能。如果单击“保存”按钮,它也会 returns -2 作为对话框结果。

感谢@CSS 的帮助(见上面的回答和评论),这是当前完整的工作代码(除非我仍然发现任何缺陷):

Private Sub Button_Dokument_mit_Grafik_als_PDF_speichern_Click()
    Dim Grafik As Boolean
    Grafik = Options.PrintDrawingObjects
    Options.PrintDrawingObjects = True

    Dim dlg As Dialog
    Dim dlgResult As Long
    Set dlg = Dialogs(wdDialogFileSaveAs)
    With dlg
        .Format = wdFormatPDF
        dlgResult = .Display
        If dlgResult = -1 Then 'user clicked save button
            If .Name <> "" Then
                If IsFileInUse(.Name) Then
                    MsgBox "The target PDF file you are trying to save is locked or used by other application." & vbCrLf & _
                    "Please close the PDF file and try again.", vbExclamation
                Else
                    .Execute
                End If
            End If
        End If
    End With

    Options.PrintDrawingObjects = Grafik
End Sub

Private Function IsFileInUse(ByVal filePath As String) As Boolean
    On Error Resume Next
    Open filePath For Binary Access Read Lock Read As #1
    Close #1
    IsFileInUse = IIf(Err.Number > 0, True, False)
    On Error GoTo 0
End Function

再次感谢@CSS。 :)

不过,您可能想要编辑您的答案,以使其确实反映最终的工作代码。我已经给予了适当的感谢。