I set up the following test procedure.
Private Sub TryPDF()
Dim oShell As Object
Dim App As String
Dim SrcPath As String
Dim Fn As String
App = "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe "
SrcPath = Environ("UserProfile") & "\Downloads\"
Fn = "20200509_Order_of_08_05_2020.PDF"
Shell App & SrcPath & Fn, vbNormalFocus ' opens the file
Set oShell = CreateObject("WSCript.Shell")
oShell.Run App & SrcPath & Fn, vbNormalFocus, True ' error -2147024894
Set oShell = Nothing
End Sub
The Shell command in the middle works, thereby proving that app and files exist as and where specified. However, I want the Wait property of the WSCript.Shell object and therefore want to open the file using the line oShell.Run App & SrcPath & Fn, vbNormalFocus, True. I have tested it as shown and without some and any parameters, which should just open the Acrobat Reader when totally stripped, and I always get the same error, "Method 'Run' of object 'IWshShell3' failed".
What am I doing wrong?
You have to escape the spaces in your paths (app and file) by surrounding them with double-Quotes, as the command-line uses them as argument separators. That would make
C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe
C.\Program a file named Program located on C: and that doesn't exists!
"C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
will work as expected on command-line.
For some reasons VBA.Shell can handle the spaces in the apppath, but WScript.Shell can't.
Both will fail on not quoted paths to file, if they contain spaces.
My prefered quoting-style is the Chr(34) function
CommanQuoted = Chr(34) & "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" & Chr(34) & " " & Chr(34)
& "...\Downloads\20200509_Order_of_08_05_2020.PDF" & Chr(34)
as it is far better readable than the also useable double double-quote
CommandQuoted = """C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"" ""...\Downloads\20200509_Order_of_08_05_2020.PDF"""
Or you can create a constant that returns a double quote
Const dquote As String = """"
CommandQuoted = dquote & "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" & dquote & " " & dquote
& "...\Downloads\20200509_Order_of_08_05_2020.PDF" & dquote
Private Sub OpenPDFWithWScripShell()
Dim oShell As Object
Dim AppPathQuoted As String
Dim SrcPathQuoted As String
Dim FileName As String
Dim shellCommand As String
AppPathQuoted = Chr(34) & "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" & Chr(34)
FileName = "20200509_Order_of_08_05_2020.PDF"
SrcPathQuoted = Chr(34) & Environ("UserProfile") & "\Downloads\" & FileName & Chr(34)
shellCommand = AppPathQuoted & " " & SrcPathQuoted
Debug.Print shellCommand
Set oShell = CreateObject("WSCript.Shell")
oShell.Run shellCommand, vbNormalFocus, True
Set oShell = Nothing
End Sub
Related
So I'm trying to make a macro that replaces the vbaProject.bin of a selected Excel workbook (in the "filename.zip/xl" folder), but I'm running into a problem with actually copying the update vbaProject.bin into the zip folder. The first line I tried (now commented out) was:
Call fso.CopyFile(tempBinFile, newFileName & "\xl\", True)
Which gave me an error that it couldn't find that path, which I assume is because it's within a zip file. So next I tried this line:
ShellApp.Namespace(newFileName & "\xl\").CopyHere tempBinFile, 16
Which didn't give an error, but also doesn't appear to have actually done anything. Is there a way to directly paste (and replace) into a subfolder of a zip file using VBA? I also tried unzipping the file first and then re-zipping, but I was getting different errors with that, so if anyone has a good solution for doing that instead, that would also be helpful.
Sub ReplaceVBABin()
Dim strFileName As String
Dim newFileName As String
Dim pathName As String
Dim tempBinFile As String
Dim xlFolderName As String
Dim fso As Object
Dim ShellApp As Object
Set ShellApp = CreateObject("Shell.Application")
Set fso = VBA.CreateObject("Scripting.FileSystemObject")
'Select file to patch
strFileName = Application.GetOpenFilename("Excel Macro Enabled Workbook (*.xlsm), *.xlsm")
If strFileName = "False" Then Exit Sub
'Rename file to .zip
newFileName = Replace(strFileName, ".xlsm", ".zip")
Name strFileName As newFileName
pathName = fso.GetParentFolderName(strFileName) & "\"
'Add copy of embedded vbaProject.bin to directory
tempBinFile = CreateTempBin(pathName)
'Copy and replace vbaProject.bin in folder
'Call fso.CopyFile(tempBinFile, newFileName & "\xl\", True)
ShellApp.Namespace(newFileName & "\xl\").CopyHere tempBinFile, 16
'Delete temp file
Kill tempBinFile
'Name zip file back to .xlsm
Name newFileName As strFileName
End Sub
Using the command line options for 7-Zip this shows the 3 steps extract,delete then update that you can adapt as required. It extracts the xl directory to a temporary folder, deletes the xl folder from the workbook and then replaces it with update. I think you can probably dispense with the delete, just extract, replace the vbaProject.bin file and then do update.
Sub ReplaceVBABin7z()
Const SevenZipExe = "C:\Program Files\7-Zip\7z.exe"
Const tmpDir = "c:\temp\7z\"
Dim qq As String: qq = Chr(34) '"
' check 7-zip exe exists
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.fileexists(SevenZipExe) Then
MsgBox SevenZipExe & " not found", vbCritical, "7-Zip Not found"
Exit Sub
End If
' create list of commands available
Dim cmd As String, pid As Double
'cmd = "cmd /c """ & SevenZipExe & """ >" & tmpDir & "7-Zip_Commands.txt"
'pid = Shell(cmd, vbHide)
'MsgBox "Command List see " & tmpDir & "7-Zip_Commands.txt", vbInformation, pid
Dim path As String
Dim strFileName As String, strBinName As String
' select workbook
path = ThisWorkbook.path & "\"
strFileName = Application.GetOpenFilename("Excel Macro Enabled Workbook (*.xlsm), *.xlsm")
If strFileName = "False" Then Exit Sub
strFileName = qq & strFileName & qq ' quoted for spaces in filename
ext:
' extract xl dir and sub dirs into tmpdir
cmd = qq & SevenZipExe & qq & " x -r -y -o" & qq & tmpDir & qq & " " & _
strFileName & " xl"
pid = Shell(cmd, vbHide)
Debug.Print pid, cmd
MsgBox "xl directory from " & strFileName & " extracted to " & tmpDir, vbInformation, "EXTRACT pid=" & pid
'Shell "Taskkill -pid " & pid
del:
' delete xl\vbaProject.bin dir and subdir
strBinName = "xl\vbaProject.bin"
cmd = qq & SevenZipExe & qq & " d -r " & _
strFileName & " " & strBinName
pid = Shell(cmd, vbHide)
Debug.Print pid, cmd
MsgBox strBinName & " deleted from " & strFileName, vbInformation, "DELETE pid=" & pid
'Shell "Taskkill -pid " & pid
upd:
' update xl dir and subdir
cmd = qq & SevenZipExe & qq & " u -r -y -stl " & _
strFileName & " " & qq & tmpDir & "xl" & qq
pid = Shell(cmd, vbHide)
Debug.Print pid, cmd
MsgBox strFileName & " updated from " & tmpDir, vbInformation, "UPDATE pid=" & pid
'Shell "Taskkill -pid " & pid
End Sub
I am getting an error on this line. Error 70: Permission Denied
wsh.Run """" & FileName & """"
I'm unsure what the problem is. This program is attempting to create a VB script inside to run asynchronously.
Private Sub CompleteUploadThread(ByVal fName As String)
Dim strScript As String, FileName As String, wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
'---Create VBscript String---
strScript = "WScript.Sleep 1000" & vbCrLf & _
"Dim wsh" & vbCrLf & _
"Set wsh = CreateObject(""WScript.Shell"")" & vbCrLf & _
"wsh.SendKeys """ & fName & """" & vbCrLf & _
"wsh.SendKeys ""{ENTER}""" & vbCrLf & _
"Set wsh = Nothing"
'---Save the VBscript String to file---
FileName = wsh.ExpandEnvironmentStrings("C:\Users\x7user\Desktop\Temp") & "\automation.vbs"
Open FileName For Output As #1
Print #1, strScript
Close #1
'---Execute the VBscript file asynchronously---
wsh.Run """" & FileName & """"
Set wsh
here's the entire code snipet
Found the problem. It was a permission issues with the folder it was in. I have to use something I have admin access to.
When I am placing the code Excel file in a folder/directory which does not have any space in it the naming conventions than it is working fine and firing the Web-Service. But when I place the code Excel file in a folder which has space in it's naming convention, I am getting a run-time error:
'-2147024894 (80070002).
Please help
Sub InvokShellScript1()
Dim sApp As String
Dim var As Integer
sApp = ThisWorkbook.Path & "\protected\WSInvoke.bat " & ThisWorkbook.Path & "\protected\Refresh.txt " & ThisWorkbook.Path
Dim objShell As Object
Set objShell = CreateObject("WScript.Shell")
var = objShell.Run(sApp, 0, True)
End Sub
You need quotes around the paths to be able to handle spaces. Try either of these:
sApp = Chr$(34) & ThisWorkbook.Path & "\protected\WSInvoke.bat" & Chr$(34) & " " & Chr$(34) & ThisWorkbook.Path & "\protected\Refresh.txt" & Chr$(34) & " " & Chr$(34) & ThisWorkbook.Path & Chr$(34)
or if Chr() doesn't work:
sApp = """" & ThisWorkbook.Path & "\protected\WSInvoke.bat"" """ & ThisWorkbook.Path & "\protected\Refresh.txt"" """ & ThisWorkbook.Path & """"
Trying to create the string for use with the Shell command in Access VB. The string works if written in full but if I try to use variables in the string the command does not work even if the use of variables produces exactly the full string, (in the immediate window), that works.
I suspect something is going on in the interpretation of the string version of the code but can't work out what.
Here's the code, I have used CHR(34) to produce the quotation marks that I want to show in the string. Suggestions would be so much appreciated - I don't have much hair left!
Private Sub temp()
Dim strFilePath As String
Dim strFileName As String
Dim strZipFilename As String
Dim strPDFfilename As String
Dim strShellString As String
Dim shell As Object
Dim result As Long
Set shell = CreateObject("WScript.shell")
strFilePath = "E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs"
strFileName = "17-03-31temp"
strZipFilename = strFilePath & "\" & strFileName & ".zip"
strZipFilename = Chr(34) & strZipFilename & Chr(34)
strPDFfilename = strFilePath & "\" & strFileName & ".pdf"
strPDFfilename = Chr(34) & strPDFfilename & Chr(34)
strShellString = Chr(34) & Chr(34) & Chr(34) & "C:\Program Files\7-Zip\7z.exe" & Chr(34) & Chr(34) & " a -tzip " & Chr(34) & strZipFilename & Chr(34) & " " & Chr(34) & strPDFfilename & Chr(34) & Chr(34)
'Non Working shell command
result = shell.Run(strShellString, 0, False)
'Working shell command
result = shell.Run("""C:\Program Files\7-Zip\7z.exe"" a -tzip ""E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs\17-03-31temp.zip"" ""E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs\17-03-31temp.pdf""", 0, False)
'Immediate Window output of strShellString
' """C:\Program Files\7-Zip\7z.exe"" a -tzip ""E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs\17-03-31temp.zip"" ""E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs\17-03-31temp.pdf"""
End Sub
My hair is saved - I worked out the answer! So, for posterity here it is.
I modified strFilePath to put quotes around the two word folder names and removed quotations from around the strZipFilename and strPDFFilename lines. I guess Shell was suffering from a surfeit of quotes.
Whilst modifying it I added a password to the zip file and changed the false to true at the end of the string command so that it would return an error code.
Thanks to anyone who spent time trying to work out what I had done.
Public Sub temp()
Dim strFilePath As String
Dim strFileName As String
Dim strZipFilename As String
Dim strPDFfilename As String
Dim strPassword As String
Dim shell As Object
Dim result As Long
Set shell = CreateObject("WScript.shell")
strPassword = "frog"
strFilePath = "E:\Documents\""Excel Spreadsheets""\""Roz Theremas""\Access\PDFs"
strFileName = "17-03-31temp"
strZipFilename = strFilePath & "\" & strFileName & ".zip"
strPDFfilename = strFilePath & "\" & strFileName & ".pdf"
result = shell.Run("""C:\Program Files\7-Zip\7z.exe"" a -tzip " & "-p" & strPassword & " " & strZipFilename & " " & strPDFfilename, 0, True)
I have a text file with 60k+ of directory lines. How can I edit each line to go from this:
C:\AJ\RPG Maker\Whisper of a Rose\OST\39 The Jewel (extended mix).mp3
To this:
ROBOCOPY "C:\AJ\RPG Maker\Whisper of a Rose\OST" "E:\AJ\RPG Maker\Whisper of a Rose\OST" "39 The Jewel (extended mix).mp3"
I was thinking about a VBScript, but I can't get any further than this because I have no knowledge of it:
Set objFS = CreateObject("Scripting.FileSystemObject")
strFile = "c:\file.txt"
Set objFile = objFS.OpenTextFile(strFile)
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
If
End If
WScript.Echo strLine
Loop
Since the FileSystemObject doesn't allow for editing a file, create a separate file to contain your output:
Set objFile2 = objFS.CreateTextFile("c:\out.txt", True)
Then, using the loop you've already created:
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
' Get the parent folder and the file name...
strFolder = objFS.GetParentFolderName(strLine)
strFile = objFS.GetFileName(strLine)
' Write the command to the new output file...
objFile2.Write "ROBOCOPY "
objFile2.Write Chr(34) & strFolder & Chr(34) & " "
objFile2.Write Chr(34) & "E" & Mid(strFolder, 2) & Chr(34) & " "
objFile2.Write Chr(34) & strFile & Chr(34) & vbCrLf
Loop
Nothing too tricky here. Just extracting parts of the file name using methods provided by the FileSystemObject and then concatenating strings to create our output. Chr(34) is used to represent a quote character in your output file.