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

I created a dialog with three buttons, where the third should save a Word document (Office Pro Plus 2013, BTW) as a PDF file.
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
If the PDF exists I can choose to overwrite it, which does work in most cases.
If the PDF to be overwritten is already open, in Adobe Reader for instance, then the file isn't saved, as it is locked. I don't get any notification that the file is locked.
How can I catch this and pop up the same message that I get when saving manually within Word?
EDIT:
To explain why my question is different to others that have been answered:
I don't need to check if the file is open in Word already. I'm saving the file as a PDF not as a Word file.
I need to check if the file is open and locked in any other application, such as Adobe Reader, Edge or whatever.
This check is done by Word (and/or the OS?) already, and THIS is the event I need to catch. I don't understand why I need to catch it at all, as the result of the check if the file does exist does come up, but the result of the check if the file is locked seems to be ignored.
The VBA code behaves as if the file has been saved, but it is not, if locked by any application other than Word.
I have no clue which code snippet exactly I would need to grab from Detect whether Excel workbook is already open

Here is what you might be looking for:
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
If you would like to use wdDialogFileSaveAs dialog, you can try the below code:
The Display method will display the dialog box without executing the actual functionality. You can validate the result of the display to identify the button clicked and use the execute method to execute the actual functionality.
'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
Please note that, the above code (wdDialogFileSaveAs dialog) doesn't work as expected in Word 2016 at least in my local enviornment. The Display method executes the actual functionality once the save button is clicked. Also it returns -2 as a dialog result if Save button is clicked.

Thanks to the help of #CSS (see answer and comments above), this is the full currently working code (unless I'd still find any flaws):
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
Thanks to #CSS again. :)
You may want to edit your answer, though, so that it does reflect the finally working code. I've given appropriate thanks.

Related

Open the file and save as another name

I want to create a new word file called "xxx_def_xxx" from selected word file called "xxx_docu_xxx".
So I select a file from dialog -> do something -> SaveAs with new file name.
It does work, but I'm getting "run time error 4160: Bad file name" if I select the file created from others, i.e., if the author is not me but another person.
I was struggling with this problem for couple of days but couldn't solve it.
Any help will be really thankful!
Private Sub CommandButton1_Click()
Dim fileOpen As FileDialog
Dim docuName As String, defName As String
Dim docu As Document
Set fileOpen = Application.FileDialog(FileDialogType:=msoFileDialogOpen)
With fileOpen
.Filters.Clear
.Filters.Add "Word Documents", "*.docx*"
.Title = "Select the docu"
.AllowMultiSelect = False
If .Show = -1 Then
docuName = .SelectedItems(1)
Else
Exit Sub
End If
End With
Set docu = Documents.Open(docuName)
'do something: remove or edit some texts in the file
defName = Replace(docu.Name, "docu", "def")
docu.SaveAs docu.Path & "\" & defName
docu.Saved = True
docu.Close
End Sub

How to search and replace across multiple word documents in the same folder?

I've tried to use the below code which I found on this conversation How To Search And Replace Across Multiple Files In Word? supplied by Charles Kenyon. However, it doesn't seem to work for me. I've enabled macros on my word and added the below code as a new module in Macros. When I go to replace all, it'll replace the text as per normal, but after doing this, when I open up the other macros enabled word doc, I find that the same text is still in these docs, without being replaced. Am I doing something wrong? Namely, I also wish to add a wildcard entry into my replace all, will the below code work or can someone suggest a better alternative? I have tested the below code with and without wildcard entries to no avail. I've also tried the code on this page in my macros but it also didn't work How to find and replace a text in multiple Word documents using VBAThanks for any help!
Option Explicit
Public Sub BatchReplaceAll()
Dim FirstLoop As Boolean
Dim myFile As String
Dim PathToUse As String
Dim myDoc As Document
Dim Response As Long
PathToUse = "C:\Test\"
'Error handler to handle error generated whenever
'the FindReplace dialog is closed
On Error Resume Next
'Close all open documents before beginning
Documents.Close SaveChanges:=wdPromptToSaveChanges
'Boolean expression to test whether first loop
'This is used so that the FindReplace dialog will
'only be displayed for the first document
FirstLoop = True
'Set the directory and type of file to batch process
myFile = Dir$(PathToUse & "*.doc")
While myFile <> ""
'Open document
Set myDoc = Documents.Open(PathToUse & myFile)
If FirstLoop Then
'Display dialog on first loop only
Dialogs(wdDialogEditReplace).Show
FirstLoop = False
Response = MsgBox("Do you want to process " & _
"the rest of the files in this folder", vbYesNo)
If Response = vbNo Then Exit Sub
Else
'On subsequent loops (files), a ReplaceAll is
'executed with the original settings and without
'displaying the dialog box again
With Dialogs(wdDialogEditReplace)
.ReplaceAll = 1
.Execute
End With
End If
'Close the modified document after saving changes
myDoc.Close SaveChanges:=wdSaveChanges
'Next file in folder
myFile = Dir$()
Wend
End Sub

Open Windows Explorer from Outlook to choose template [duplicate]

This question already has answers here:
Filepicker VBA to select file and store the file name not working
(2 answers)
Closed 3 years ago.
I am trying to write a macro that allows a user to select a .oft from a directory. I have been able to get a simple macro working that will open a specific .oft and modify the "from" field - this is what I have so far.
Sub EmailTemplateW10()
Set msg = Application.CreateItemFromTemplate("c:\test\test.oft")
msg.SentOnBehalfOfName = "user#domain.com"
msg.Display
Set msg = Nothing
End Sub
That works great, but there are numerous .oft files in the directory I am working with. I did find some articles that talk about setting up a toolbar with drop-downs and creating a macro for each .oft in the directory. I assume there has to be a better way than making a macro for each template.
I tried using this :
Sub EmailTemplateW10()
Set msg = Application.CreateItemFromTemplate(Demo)
msg.SentOnBehalfOfName = "user#domain.com"
msg.Display
Set msg = Nothing
End Sub
Function Demo()
Call Shell("explorer.exe" & " " & "C:\test\", vbNormalFocus)
End Function
Windows Explorer will come up - but the macro throws an error and stops when you acknowledge the error.
Is there perhaps some way to have the user select the file through explorer.exe and save the path of the selected file to a variable, and then pipe that into .CreateItemFromTemplate?
After some digging around I got this to work. I am obviously a VBA noob so i take no credit for the code - I was just able to mash it together and get it to work. Maybe someone in the future will find it helpful.
Public Function aBrowseForFile(aStartFolder As String) As String
On Error GoTo Err_txtBrowseForFile
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = False
Dim fDialog As Office.FileDialog
Dim varfile As Variant
Dim strPath As String
Dim strFilter As String, strFileName As String
Dim Main_Dir As String, DefFolder As String
Set fDialog = xlApp.Application.FileDialog(msoFileDialogFilePicker)
With fDialog
.InitialView = msoFileDialogViewThumbnail
.AllowMultiSelect = False
.Title = "Please select one or more files"
.InitialFileName = aStartFolder
.InitialView = msoFileDialogViewThumbnail
.Filters.Clear
.Filters.Add "all files", "*.*"
If .Show = True Then
aBrowseForFile = .SelectedItems(1)
Else
MsgBox "You clicked Cancel in the file dialog box."
End If
End With
Exit_txtBrowseForFile:
Exit Function
Err_txtBrowseForFile:
MsgBox Err.Description, vbCritical, "MyApp"
Resume Exit_txtBrowseForFile
End Function
Sub EmailTemplateW10()
Dim MyFileURL As String
MyFileURL = aBrowseForFile("C:\users\")
Set msg = Application.CreateItemFromTemplate(MyFileURL)
msg.SentOnBehalfOfName = "user#domain.com"
msg.Display
Set msg = Nothing
End Sub

MSAccess - Run-time error '438': Object doesn't support this property or method

I'm running into an error when I attempt to add filters to a FileDialog.
I've tried to troubleshoot this with multiple posts / articles but nothing seems to have solved it. The online documentation identifies using .Filters.Add but it doesn't seem that .Filters is an appropriate method. .Filter.Add is at least recognized but is still invalid. .Filter.Clear is also recognized but is invalid as well.
Code:
Private Sub Command93_Click()
Dim objFD As Object, strOut As String
Set objFD = Application.FileDialog(2)
With objFD
.Filter.Clear
.Filter.Add "Excel File", ".xls"
If objFD.show = -1 Then
strOut = objFD.selecteditems(1)
End If
End With
Set objFD = Nothing
Me.txtSaveFile = strOut
Me.Refresh
End Sub
Ok here is the answer. First, thanks to the above shots at solving for the issue as they did lead to me reviewing the documentation (again) and making another attempt. The first answer put me on to the issue as .Filters simply won't work with a msoFileSaveAs dialog. However, you can't type in a different file name on an Open dialog (either 1 or 3).
So the answer is to use msoFileSaveAs or (2) and use the .Initialfilename property to set the extension which, in this case, will show a list of excel files which can be selected, or selected and modified and then you can click on "Save"
Working code:
Private Sub Command93_Click()
Dim objFD As Object
Dim strOut As String
Set objFD = Application.FileDialog(2)
With objFD
'.Filters.Clear
'.Filters.Add "Excel File", "*.xls; *.xlsx", 1
.Initialfilename = "*.xlsx"
If .show = -1 Then
strOut = objFD.selecteditems(1)
End If
End With
Set objFD = Nothing
Me.txtSaveFile = strOut
Me.Refresh
End Sub
Thanks all!
You are using the the filters with the wrong dialog box. .Filters will work with msoFileDialogOpen which has a value of 1 or with msofiledialogfilepicker which has a value of 3. So try .Filters with Application.FileDialog(1) or Application.FileDialog(3) as shown below and it will work but it will not work with the msofiledialogsaveas which has a value of 2
The constants msoFileDialogOpen and msoFileDialogSaveAs are not supported in Microsoft Access. What it doesn't mean: is that the Application.FileDialog is NOT suported. What it means: is the constants are not supported. If you type ?msoFileDialogOpen in Immediate Window in MS Access, you will not see any value and hence we have to pass those values literally or declare them.
You have to use .Filters instead of .Filter
See this example
Option Explicit
Const msoFileDialogOpen As Integer = 1
Sub Sample()
Dim f As Object
Dim i As Long
Set f = Application.FileDialog(msoFileDialogOpen)
With f
.Filters.Clear
.Filters.Add "Excel File", "*.xls*"
.AllowMultiSelect = True
If .Show Then
For i = 1 To .SelectedItems.Count
MsgBox .SelectedItems(i)
Next
End If
End With
End Sub
Screenshot
EDIT:
If you want to use Filters in while saving then check out the link Display Open and Save As Dialog Boxes in Access with API Functions
Here you will see how to use filters in the using the .SaveFileDialog using the CommonDialogAPI

Excel VBA - Save As Dialog Window - stop code from continuing if "cancel" is pressed?

I currently use the following code to force the user to save the file as a macro enabled workbook.
Application.Dialogs(xlDialogSaveAs).Show , xlOpenXMLWorkbookMacroEnabled
The problem is, if the user presses the "Cancel" button, the code continues on. I need to it to stop if the "Cancel" button is pressed.
Any help is appreciated.
Thanks.
You will have to capture the event when the cancel button is clicked.
Sub saveasxml()
Dim userResponce As Boolean
On Error Resume Next
userResponce = Application.Dialogs(xlDialogSaveAs).Show("Test name", 52)
On Error GoTo 0
If userResponce = False Then
MsgBox "Cancel clicked"
Exit Sub
Else
MsgBox "You saved file "
End If
End Sub
This page has a nice example that explains what you need to do:
http://codevba.com/excel/dialogs.htm#SaveAs
Essentially, it's like this:
' Application.Dialogs(xlDialogSaveAs).Show returns
' True or False depending on whether the user canceled or not
If Application.Dialogs(xlDialogSaveAs).Show Then
' User saved
Else
' User canceled
End If
Taking a more complete example from the link above and modifying it slightly to your purposes:
Sub thing()
Dim strFilename As String: strFilename = "report1"
Dim strFolder As String: strFolder = "C:\temp\" 'initial directory - NOTE: Only works if file has not yet been saved!
'Dim xlfFileFormat As XlFileFormat: xlfFileFormat = XlFileFormat.xlOpenXMLWorkbook 'or replace by other XlFileFormat
Dim xlfFileFormat As XlFileFormat: xlfFileFormat = XlFileFormat.xlOpenXMLWorkbookMacroEnabled 'or replace by other XlFileFormat
Dim strPassword As String: 'strPassword = "password" 'The password with which to protect the file - if any
Dim booBackup As Boolean: 'booBackup = True '(Whether to create a backup of the file.)
Dim strWriteReservationPassword As String: 'strWriteReservationPassword = "password2" ' (The write-reservation password of the file.)
Dim booReadOnlyRecommendation As Boolean: booReadOnlyRecommendation = False '(Whether to recommend to the user that the file be opened in read-only mode.)
Dim booWorkbookSaved As Boolean ' true if file saved, false if dialog canceled
If Len(strFolder) > 0 Then ChDir strFolder
booWorkbookSaved = Application.Dialogs(xlDialogSaveAs).Show(Arg1:=strFilename, Arg2:=xlfFileFormat, Arg3:=strPassword, _
Arg4:=booBackup, Arg5:=strWriteReservationPassword, Arg6:=booReadOnlyRecommendation)
If Not booWorkbookSaved Then
Exit Sub
End If
MsgBox "Workbook saved"
End Sub