I'm using VBA in Excel to loop through files on a sharepoint site and open all Excel files.
The code crashes Excel the first time I run it, however, if I then reopen it it works fine.
Are there any known issues around this?
Thanks.
Edit: Here is the code:
Sub Refresh()
With Application
.ScreenUpdating = False
.DisplayAlerts = False
Dim fso As FileSystemObject
Dim fldr As Folder
Dim f As File
Dim wb As Workbook
Set fso = New FileSystemObject
Set fldr = fso.GetFolder(SharePointSite)
For Each f In fldr.Files
Set wb = Workbooks.Open(SharePointURL & f.Name)
Next f
Set wb = Nothing
Set fldr = Nothing
Set fso = Nothing
.DisplayAlerts = True
.ScreenUpdating = True
End With
End Sub
Instead of mapping the document library to a drive letter try using the WebDAV address to access the library in your code. This way if the macro is distributed no one will be dependent upon having the "Z:" drive being mapped to a specific location
Set your FilePath variable equal to a string like this (use #SSL for HTTPS sites):
\\sharepoint.site.com#SSL\DavWWWRoot\site1\usersite\Book2\Shared%20Documents
If you are going to access the text file directly then set it up like this:
\\sharepoint.site.com#SSL\DavWWWRoot\site1\usersite\Book2\Shared%20Documents
\Test_Text1.txt
Take a look at this blog post for a full explanation on retrieving the WebDAV path.
Related
I am trying to write some macros in both Excel and Outlook that in the end will automatically unzip and open a CSV, process the data, and sends it where it needs to go when a new email arrives in a specific folder. I have everything worked out on the Excel side but I am having difficulties with Outlook. The below code unzips the file. How would i go about opening the unzipped file and triggering an Excel macro (which is always open in another workbook)?
Another issue I am running into: this code only seems to work when i actually open the target email in it's own window.
Public Sub OpenZippedSheet()
Dim objMail As Outlook.MailItem
Dim objAttachments As Outlook.Attachments
Dim objAttachment As Outlook.Attachment
Dim objShell As Object
Dim objFileSystem As Object
Dim strTempFolder As String
Dim strFilePath As String
Dim strFileName As String
Set objMail = Outlook.Application.ActiveInspector.CurrentItem
Set objAttachments = objMail.Attachments
'Save & Unzip the zip file in local drive
Set objShell = CreateObject("Shell.Application")
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
strTempFolder = objFileSystem.GetSpecialFolder(2).Path & "\Temp" & Format(Now, "yyyy-mm-dd-hh-mm-ss")
MkDir (strTempFolder)
For Each objAttachment In objAttachments
If Right(objAttachment.FileName, 3) = "zip" Then
strFilePath = strTempFolder & "\" & objAttachment.FileName
objAttachment.SaveAsFile (strFilePath)
objShell.NameSpace((strTempFolder)).CopyHere objShell.NameSpace((strFilePath)).Items
End If
Next
End Sub
I'm assuming I would do some sort of object.open but I don't know what the syntax would be to get it to actually open in Excel. And then is there a way to trigger an Excel macro from Outlook?
Thanks so much in advance!
this code only seems to work when i actually open the target email in it's own window.
That is because you rely on the ActiveInspector window. If you want to handle items selected in the Explorer windows you need to check the Selection object (see the corresponding property).
To open an Excel file you can:
Use the Shell.ShellExecute method. This method is equivalent to launching one of the commands associated with a file's shortcut menu. Each command is represented by a verb string. The set of supported verbs varies from file to file. The most commonly supported verb is "open", which is also usually the default verb. Other verbs might be supported by only certain types of files.
Automate Excel from your VBA macro to do the required actions. See How to automate Microsoft Excel from Visual Basic for more information.
To run your VBA macro code from other applications you can use the Application.Run method. Read more about that in the How do I use Application.Run in Excel article.
Application.Run "'" & TestWkbk.Name & "'!MacroNameHere", "parm1", "parm2"
Something like this (untested so may need some fixes):
'Note - any paths passed to objShell should be
' passed as *Variants*, not Strings
Dim oXL As Object, wbCSV As Object, fileNameInZip As Variant
Set objShell = CreateObject("Shell.Application")
For Each objAttachment In objAttachments
If Right(objAttachment.Filename, 3) = "zip" Then
strFilePath = strTempFolder & "\" & objAttachment.Filename
objAttachment.SaveAsFile strFilePath
Set oNS = oApp.Namespace(strFilePath)
For Each fileNameInZip In oNS.items 'loop over the files in the zip
Debug.Print fileNameInZip
If LCase(fileNameInZip) Like "*.csv" Then 'csv file?
'extract the file
objShell.Namespace(strTempFolder).copyhere oNS.items.Item(CStr(fileNameInZip))
If oXL Is Nothing Then Set oXL = GetObject(, "Excel.Application") 'assumes excel is running
Set wbCSV = oXL.Workbooks.Open(strTempFolder & "\" & fileNameInZip)
oXL.Run "'YourMacroFile.xlsm'!YourMacroName" 'run the macro
'clean up stuff...
End If 'is a csv file
Next 'file in zip
End If 'attachment is a zip file
Next 'attachment
I know it might be a silly mistake but I tried many ways of doing that and none of them worked.
I have this code in place for grabbing data from other excel sheets in a folder and pasting it in a master folder. The issue pops up when I try to use wildcards to look for files where part of the name is variable. In the example below, the file name is Stock_RTC_17.02.2019.xlsx.
However, excel returns an error that the file is not found in the folder for the code below, even though you can see it has found the correct file name. Anyone got a clue on what I'm doing wrong?
Sub copytest() 'Procedure for retrieving data from the sourcefiles
Dim wbTarget, wbSource As Workbook
Dim target As Object
Dim pathSource As String
Dim xlApp As Application
'path where the data source folders are located (please keep all of them in the same directory)
pathSource = "C:\Users\vferraz\Desktop\crm stock\RAPOARTE IMPORTANTE\18.02\Rapoarte pentru Handsets\"
Set wbTarget = ThisWorkbook
Set xlApp = CreateObject("Excel.Application")
xlApp.DisplayAlerts = False
Application.CutCopyMode = False
'Stock RTC
Dim FileName As String
FileName = Dir(pathSource & "Stock_RTC_*.xlsx", vbNormal)
Set wbSource = xlApp.Workbooks.Open(FileName)
wbSource.Sheets(1).UsedRange.Copy
wbSource.Close
Set target = wbTarget.Sheets("Stock Aberon GW TKR")
target.UsedRange.Clear
Range("A1").Select
target.Paste
End Sub
I think pathSource is not the current working directory, so you should write:
Set wbSource = xlApp.Workbooks.Open(pathSource & FileName)
You are missing the path when you try to open the workbook.
Set wbSource = xlApp.Workbooks.Open(pathSource & FileName)
I wondered if anyone can shed some light on why opening a Word document would take a few seconds from Excel? The code below quickly finds/opens a specific subfolder using InStr i.e. debug.print of the subfolder name is immediate, however opening the specific Word doc takes about 4 seconds. I tried testing a similar procedure in Word itself it opened the document almost immediately. I'm still learning VBA and I'm not sure what the reason would be other than its something to do with the last bit re strFile
Any suggestions would be appreciated.
Sub LoopSubfolderAndFiles()
Dim fso As Object
Dim folder As Object
Dim subfolder1 As Object
Dim strTextFind1 As String
Dim strFileFound As String
Dim CurrFile As Object
Dim myFile As Object
Dim strFile As String
Dim strExtension As String
Dim wordApp As New Word.Application
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder("Enter FILEPATH name..........")
Set subfolder1 = folder.subfolders
strTextFind1 = "useful"
strFileFound = "test"
strExtension = ".doc"
For Each subfolder1 In subfolder1
If InStr(1, subfolder1.Name, strTextFind1, vbTextCompare) > 0 Then
Set CurrFile = fso.GetFolder(subfolder1)
Debug.Print subfolder1.Name
Exit For
End If
Next
For Each CurrFile In CurrFile.Files
If InStr(1, CurrFile.Name, strFileFound, vbTextCompare) > 0 Then
Set myFile = fso.GetFile(CurrFile)
strFile = myFile.Path
wordApp.Visible = True
wordApp.Documents.Open (strFile)
Debug.Print strFile
End If
Next
Set fso = Nothing
Set folder = Nothing
Set subfolder1 = Nothing
Set CurrFile = Nothing
End Sub
There is nothing substantive wrong with your code. Word is slow.
The difference could be inprocess vs outofprocess. Out of Process calls are made using the RPC networking remote call procedure. Hidden windows are created so messages can be received. It's all very complicated so out of process calls work under all circumstances. In Process Calls are just a machine code jump instruction. Several clock cycles vs tens of thousands or more.
There are some minor issues.
These lines are pointless. This is handled at the end of each line for implicit variables and every end function etc for explicit variables. See Declaring Variables Memory Leaks
Set fso = Nothing
Set folder = Nothing
Set subfolder1 = Nothing
Set CurrFile = Nothing
If you want to do this indirection then they need to be const. The compiler will put them into the line where used as literals. Use variables only where needed.
strTextFind1 = "useful"
strFileFound = "test"
strExtension = ".doc"
So
const strTextFind1 = "useful"
const strFileFound = "test"
const strExtension = ".doc"
You are late binding to FSO. Use early binding as you do for Word. See Pointers needed for speeding up nested loop macro in VBA. Then instead of Dim folder As Object dim it as you do word.
Looking at your code, it's not just opening the document, it's also starting a new instance of the Word application*. So there are a number of factors that are taking time:
Starting Word. Have you ever timed how long it takes Word to start when you click the icon? First, the application itself needs to load. Then, there may be any number of add-ins loading, which will take time.
When an outside application "automates" another application there is a time "hit" for the "cross-barrier" communication. VBA within an Office application is usually quite fast; the same commands run from a different application will be (noticeably) slower.
'* You should never declare and instantiate an application in the same line in VBA. You should change your code to:
Dim wordApp as Word.Application
Set wordApp = New Word.Application
Good Morning All,
I have fought with this for a few days now, and have not yet found a suitable solution, so I hope somebody can put me out of my misery!
From within an excel document, I have 3 buttons to check out and open 3 documents from a Microsoft Sharepoint Server. 2 files are Excel workbooks, and one is a Word document.
The excel files work absolutely fine, but the Word document always returns 'False' when the .CanCheckOut statement is reached, even though I can manually check it out on MOSS, have the correct permissions etc. I have added the Microsoft Word 11.0 Object Library reference in my Excel VBA.
Here is my code for the excel ones:
Sub CheckOutXL(FullPath As String)
Dim xlApp As Object
Dim wb As Workbook
Dim xlFile As String
xlFile = FullPath
Set xlApp = CreateObject("Excel.Application")
'Determine if workbook can be checked out.
If Workbooks.CanCheckOut(xlFile) = True Then
'Check out file
Workbooks.CheckOut xlFile
'Open File
Set xlApp = New Excel.Application
xlApp.Visible = True
Set wb = xlApp.Workbooks.Open(xlFile, , False)
'Otherwise offer the option to open read-only
Else
If (MsgBox("You are unable to check out this document at this time, would you like to open it read-only?", vbYesNo) = vbYes) Then
Set xlApp = New Excel.Application
xlApp.Visible = True
Set wb = xlApp.Workbooks.Open(xlFile, , False)
End If
End If
and for the Word one:
Sub CheckOutDoc(FullPath As String)
If Documents(docFile).CanCheckOut = True Then 'This is the one that returns FALSE
Documents.CheckOut docFile
' Set objWord = CreateObject("Word.Application") 'The commented out section was
' objWord.Visible = True 'a second way I tried to open
' objWord.Documents.Open docFile 'the file.
Documents.Open Filename:=docFile
Else
If (MsgBox("You are unable to check out this document at this time, would you like to open it read-only?", vbYesNo) = vbYes) Then
Documents.Open Filename:=docFile
End If
End If
End Sub
These are both called using a simple line for each button as such:
Private Sub btnTrend_Click()
Call CheckOutXL("FullPathOfTheFileInHere.xls")
End Sub
Any help massively appreciated!! Thanks
We are having the same issue. Can you try this:
If CBool(Documents(docFile).CanCheckOut) = True Then
I have the following workbook setup:
Workbook A has a link to x amount of workbook B's and fetches data from them. The workbooks B have links to some other workbooks and fetches data from them.
Workbook A is a kind of "summary" of what all the other workbooks contains. As it is now, I have to open all my workbook Bs, refresh them and save before I open workbook A. If I don't do this the workbook B's will not be updated with the data in the workbooks C.
Is it possible to update all the workbook B's using a .bat or vbs script? or is it possible to update them from within workbook A?
I might add that I use excel starter on this computer so preferly the solution would be compatible with that.
Attached is one potential solution for this as a vbs that can be run from vba if that is available
Thanks to Sid Rout for his suggested edits to RecursiveFile(objWB)
Caution: It is possible that too many simultaneous books being open (I got to 512 during vbs recursion hell) will lead to memory issues - in that case each major branch should be updated in turn, then those workbooks closed before proceeding to the next branch.
What it does
Opens up a workbook held by strFilePath
checks whether there are any linked workbooks in 1 , if so opens them (B, B1, B2 etc)
the code then looks for any links in each of the workbooks from (2), then opens all these in turn (C1 and C2 for B etc)
each open book name is stored in an array, Arr
When all the books are opened, the initial workbook will have been updated, the recursive code ends, and all the open books except strFilePath are closed without saving
strFilePath is then saved and closed
the code tidies up
EDIT: Updated code to fix the vbs recursion issue
Public objExcel, objWB2, lngCnt, Arr()
Dim strFilePath, vLinks
`credit to Sid Rout for updating `RecursiveFileRecursiveFile(objWB)`
Erase Arr
lngCnt = 0
Set objExcel = CreateObject("Excel.Application")
strFilePath = "C:\temp\main.xlsx"
With objExcel
.DisplayAlerts = False
.ScreenUpdating = False
.EnableEvents = False
End With
Set objWB = objExcel.Workbooks.Open(strFilePath, False)
Call RecursiveFile(objWB)
For Each vArr In Arr
objExcel.Workbooks(vArr).Close False
Next
objWB.Save
objWB.Close
Set objWB2 = Nothing
With objExcel
.DisplayAlerts = True
.ScreenUpdating = True
.EnableEvents = True
.Quit
End With
Set objExcel = Nothing
MsgBox "Complete"
Sub RecursiveFile(objWB)
If Not IsEmpty(objWB.LinkSources()) Then
For Each vL In objWB.LinkSources()
ReDim Preserve Arr(lngCnt)
'MsgBox "Processing File " & vL
Set objWB2 = objExcel.Workbooks.Open(vL, False)
Arr(lngCnt) = objWB2.Name
lngCnt = lngCnt + 1
RecursiveFile objWB2
Next
End If
End Sub
Working ScreenShots
yes, you can loop through all the source B workbooks, opening them in the background and set the UpdateLinks flag to True ...
strFiles=Dir(*path & \.xls*)
do
workbooks.open strfiles, UpdateLinks:=true
workbooks(strfiles).close savechanges:=true
strFiles=Dir
loop while strfiles<>""
that should give you a start
So, as VBA is not an option, let's try a VB Script solution:
dim objFSO, objExcel, objWorkbook, objFile
'
set objExcel= CreateObject("Excel.application")
'
objExcel.visible=false
objExcel.displayalerts=false
'
Set objFSO = CreateObject("Scripting.FileSystemObject")
objStartFolder = path
'
Set objFolder = objFSO.GetFolder(objStartFolder)
' get collection of files from folder
Set colFiles = objFolder.Files
' begin loop through all files returned by Files collection of Folder object
For Each objFile in colFiles
' sanity check, is the file an XLS file?
if instr(objfile.name,"xls")<>0 then ' could also use right(objfile.name,4)=...
Wscript.Echo "Opening '" objFile.Name & "' ..."
set objWorkbook=objexcel.workbooks.open objfile.name, updatelinks:=true
objexcel.workbooks(objfile.name).close savechanges:=true
end if
Next
' close Excel
objexcel.quit
' kill the instance and release the memory
set objExcel=nothing
try that and see how you get on
and here is the VB Script SDK: MSDN Library - VB Script