I have the following code to download a single file from a share point site:
Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" _ Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
ByVal szURL As String, ByVal szFileName As String, _
ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Dim Ret As Long
Sub Report_download()
Dim strURL As String
Dim strPath As String
Dim strFile As String
strFile = "report.Denial." & Format(sDate, "yyyymmdd") & ".xlsx"
strURL = "https://sharepoint.com/HumanResources/Shared%20Documents/report.Denial.xlsx"
strPath = sPATH & strFile
Ret = URLDownloadToFile(0, strURL, strPath, 0, 0)
If Ret = 0 Then
' MsgBox "File successfully downloaded"
Else
MsgBox "Returncode:" & Ret & " Unable to download"
End If
End Sub
My question is this. I have 3 files to download from the same site. Links are the same, except of course, the report name. Is there a way that this code can be rewritten as loop to download the 3 files I need from this URL?
thank you
This should do what you want.
Option Explicit
Sub btnSharePointFolder()
Dim sht As Worksheet
Set sht = ThisWorkbook.Sheets("SharePoint Download")
If sht.Range("SharePointPath") = "" Then
MsgBox "Please enter a sharepoint path first", vbCritical
Exit Sub
End If
If Right(sht.Range("SharePointPath"), 1) <> "/" Then
'SharePointPath: http://testdrive.sharepoint.ckannan.blogspot.com/teams/YourTeam/
sht.Range("SharePointPath") = sht.Range("SharePointPath") & "/"
End If
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = sht.Range("SharePointPath")
.Title = "Please select a location of input files"
.Show
If Not .SelectedItems.Count = 0 Then
sht.Range("SharepointFolder") = .SelectedItems(1)
Else
Exit Sub
End If
End With
' 'To Remove Drive
' Shell "net use Q: /delete"
If Dir("Q:\", vbDirectory) = "" Then
Shell "net use Q: " & sht.Range("SharePointPath").Value '/user:MyDomain\MyUserName MyPassword
End If
End Sub
'_________________________________________________________________________________
Sub MapNetworkDrive()
If Dir("Q:\", vbDirectory) = "" Then
'SharePointPath: http://testdrive.sharepoint.ckannan.blogspot.com/teams/YourTeam/
Shell "net use Q: " & ThisWorkbook.Sheets("SharePoint Download").Range("SharePointPath").Value '/user:MyDomain\MyUserName MyPassword
MsgBox "The sharepoint path is mapped as network drive.", vbInformation
Else
MsgBox "The mapped network drive already exists.", vbInformation
End If
End Sub
'_________________________________________________________________________________
Sub DownloadFiles()
Dim Directory As String
Dim file As String
Dim i As Long
Dim fso As FileSystemObject
Application.ScreenUpdating = False
If Dir("Q:\", vbDirectory) = "" Then
MsgBox "There is no mapped network drive", vbCritical
Exit Sub
End If
'DownloadFolder: http://testdrive.sharepoint.ckannan.blogspot.com/teams/YourTeam/Shared Documents/PDW Status
Directory = "Q:\" & ThisWorkbook.Sheets("SharePoint Download").Range("DownloadFolder").Value & "\"
Set fso = CreateObject("Scripting.FileSystemObject")
' Get first file
file = Dir(Directory, vbReadOnly + vbHidden + vbSystem)
If file = "" Then
MsgBox "No files found in the sharepoint folder.", vbCritical
Exit Sub
End If
Do While file <> ""
fso.CopyFile Directory & file, "C:\", True
file = Dir()
Loop
Application.StatusBar = False
MsgBox "Downloaded all files to the local folder.", vbInformation
End Sub
'_________________________________________________________________________________
Sub btnLocalFolder_Click()
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = "C:\"
.Title = "Please select a location to download files"
.Show
If Not .SelectedItems.Count = 0 Then
ThisWorkbook.Sheets("SharePoint Download").Range("LocalFolder") = .SelectedItems(1)
End If
End With
End Sub
Related
Is there a way to edit the following VBA code in a way that it can also convert all .doc documents in sub folders and delete the original .doc?
I have quite many of them and I am not quite familiar with VBA code. Any help would be much appreciated!
Sub ConvertBatchToDOCX()
Dim sSourcePath As String
Dim sTargetPath As String
Dim sDocName As String
Dim docCurDoc As Document
Dim sNewDocName As String
' Looking in this path
sSourcePath = "H:\Vanhuspalvelut\Kotihoito\Tammelan_kotihoito\TURVALLISUUS\Pelastussuunnitelmaan_tuleva\TURVALLISUUS_SUUNNITELMA_2015"
sTargetPath = "H:\Vanhuspalvelut\Kotihoito\Tammelan_kotihoito\TURVALLISUUS\Pelastussuunnitelmaan_tuleva\TURVALLISUUS_SUUNNITELMA_2015"
' Look for first DOC file
sDocName = Dir(sSourcePath & "*.doc")
Do While sDocName <> ""
' Repeat as long as there are source files
'Only work on files where right-most characters are ".doc"
If Right(sDocName, 4) = ".doc" Then
' Open file
Set docCurDoc = Documents.Open(FileName:=sSourcePath & sDocName)
sNewDocName = Replace(sDocName, ".doc", ".docx")
With docCurDoc
.SaveAs FileName:=sTargetPath & sNewDocName, _
FileFormat:=wdFormatDocumentDefault
.Close SaveChanges:=wdDoNotSaveChanges
End With
End If
' Get next source file name
sDocName = Dir
Loop
MsgBox "Finished"
End Sub
Please use the next solution:
Add the next API function on top of the module (in the declarations area):
Private Declare PtrSafe Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As LongPtr)
Use the next adapted Sub:
Sub ConvertBatchToDOCX()
Dim mainFolderPath As String, sDoc, arrDocs, boolProblematic As Boolean
Dim docCurDoc As Document, sNewDocName As String, strMsg As String
' Looking in this path
mainFolderPath = "H:\Vanhuspalvelut\Kotihoito\Tammelan_kotihoito\TURVALLISUUS\Pelastussuunnitelmaan_tuleva\TURVALLISUUS_SUUNNITELMA_2015\"
strMsg = "Problematic files: " & vbCrLf
arrDocs = getAllDocs(mainFolderPath & "*.doc")
If arrDocs(0) = "" Then MsgBox "No appropriate documents have been found...": Exit Sub
For Each sDoc In arrDocs
sNewDocName = Left(sDoc, InStrRev(sDoc, ".") - 1) & ".docx": ' Stop
boolProblematic = False
On Error Resume Next
Set docCurDoc = Documents.Open(FileName:=sDoc)
If Err.Number = 5174 Then
Err.Clear: boolProblematic = True
strMsg = strMsg & sDoc & vbCrLf
End If
If Not boolProblematic Then
docCurDoc.SaveAs FileName:=sNewDocName, FileFormat:=wdFormatDocumentDefault
docCurDoc.Close False
Kill sDoc
Sleep 1000
End If
Next
If strMsg <> "Problematic files: " & vbCrLf Then MsgBox strMsg
MsgBox "Finished"
End Sub
The function has also been adapted, in order to handle the case of not document with extension ".doc" has been found:
Private Function getAllDocs(strFold As String, Optional strExt As String = "*.*") As Variant
Dim arrD, arrExt, arrFin, sDoc, i As Long
arrD = Filter(Split(CreateObject("wscript.shell").Exec("cmd /c dir """ & strFold & strExt & """ /b /s").StdOut.ReadAll, vbCrLf), "\")
ReDim arrFin(UBound(arrD))
For Each sDoc In arrD
arrExt = Split(sDoc, ".")
If LCase(arrExt(UBound(arrExt))) = "doc" Then
arrFin(i) = sDoc: i = i + 1
End If
Next
If i > 0 Then
ReDim Preserve arrFin(i - 1)
Else
ReDim arrFin(0)
End If
getAllDocs = arrFin
End Function
Maybe this could get you on the right track? (Untested)
Sub saveDOCsAsDOCXs()
ChDir "C:\myFolderName\"
Dim fIn As String, fOut As String, doc As Document
fIn = Dir("*.doc") 'list first `doc` files in current folder (includes `docx`)
Do
If Right(fIn, 4) = ".doc" Then 'only process `doc` files
Debug.Print "Opening " & fIn
Set doc = Documents.Open(fIn) 'open the `doc`
fOut = fIn & "x" 'output filename
If Dir(fOut) <> "" Then
Debug.Print fOut & " already exists." 'could instead delete existing like `Kill fOut`
Else
doc.SaveAs fOut, wdFormatXMLDocument 'save as `docx`
Debug.Print "Saved " & fOut
End If
doc.Close 'close the file
End If
fIn = Dir() 'get next `doc` file
Loop While fIn <> ""
End Sub
Documentation: Open, SaveAs2, Dir
I want to print all emails and attachments of an Outlook folder. I want to print excel, word and pfd files.
This works but not in the right order. Emails en printed attachments get mixed-up. So i want to synchronize the printing. The process has to wait until the print job has been send. The problem is probably that ShellExecute command works asynchronically from the VBA.
So how can I let the VBA wait until the ShellExecute has finished. I've read on the MSDN that I have to use the CreateProcess but I don't know how to use a print command on this. It only runs an application.
I also tried to use the Sleep method in VBA to give the printing some time but it doesn't seems to be the right solution or work very good. Please has anyone an advice?
Private Declare Function ShellExecute Lib "shell32.dll" Alias _
"ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, _
ByVal lpFile As String, ByVal lpParameters As String, _
ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal Milliseconds As LongPtr)
Sub SaveBijlageArgumenten()
SaveEmailAttachmentsToFolder "Postvak IN", "Account...", "xlsx", "xls", "pdf", "doc", "docx", "C:\....."
End Sub
Sub SaveEmailAttachmentsToFolder(OutlookInbox As String, OutlookAccount As String, _
ExtString As String, ExtString2 As String, ExtString6 As String, ExtString3 As String, ExtString4 As String, _
ExtString5 As String, DestFolder As String)
Dim ns As NameSpace
Dim Inbox As MAPIFolder
Dim SubFolder As MAPIFolder
Dim Item As Object
Dim Atmt As Attachment
Dim FileName As String
Dim MyDocPath As String
Dim I As Integer
Dim wsh As Object
Dim fs As Object
Dim xlApp As Object
Dim myBook As Object
' Create Excel Application
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = False 'Visible is False by default, so this isn't necessary
On Error GoTo ThisMacro_err
Set ns = GetNamespace("MAPI")
Set Inbox = ns.Folders(OutlookAccount)
Set SubFolder = Inbox.Folders(OutlookInbox)
I = 0
' Check subfolder for messages and exit of none found
If SubFolder.Items.Count = 0 Then
MsgBox "There are no messages in this folder : " & OutlookFolderInInbox, _
vbInformation, "Nothing Found"
Set SubFolder = Nothing
Set Inbox = Nothing
Set ns = Nothing
Exit Sub
End If
'Create DestFolder if DestFolder = ""
Set fs = CreateObject("Scripting.FileSystemObject")
If DestFolder = "" Then
Set wsh = CreateObject("WScript.Shell")
Set fs = CreateObject("Scripting.FileSystemObject")
MyDocPath = wsh.SpecialFolders.Item("mydocuments")
DestFolder = MyDocPath & "\" & Format(Now, "dd-mmm-yyyy hh-mm-ss")
If Not fs.FolderExists(DestFolder) Then
fs.CreateFolder DestFolder
End If
Else
DestFolder = DestFolder & "\" & Format(Now, "dd-mmm-yyyy hh-mm-ss")
If Not fs.FolderExists(DestFolder) Then
fs.CreateFolder DestFolder
End If
End If
If Right(DestFolder, 1) <> "\" Then
DestFolder = DestFolder & "\"
End If
'On Error Resume Next
' Check each message for attachments and extensions
For Each Item In SubFolder.Items
Item.PrintOut Background:=False
Item.UnRead = False
Sleep 500
For Each Atmt In Item.Attachments
If LCase(Right(Atmt.FileName, Len(ExtString))) = LCase(ExtString) Or _
LCase(Right(Atmt.FileName, Len(ExtString2))) = LCase(ExtString2) Then
FileName = DestFolder & Item.SenderName & " " & Atmt.FileName
Atmt.SaveAsFile FileName
Set myBook = xlApp.Workbooks.Open(FileName, UpdateLinks:=0)
myBook.PrintOut Background:=False
myBook.Close SaveChanges:=False
I = I + 1
ElseIf LCase(Right(Atmt.FileName, Len(ExtString3))) = LCase(ExtString3) Or LCase(Right(Atmt.FileName, Len(ExtString4))) = LCase(ExtString4) _
Or LCase(Right(Atmt.FileName, Len(ExtString5))) = LCase(ExtString5) Then
FileName = DestFolder & Item.SenderName & " " & Atmt.FileName
Atmt.SaveAsFile FileName
ShellExecute 0, "print", FileName, vbNullString, vbNullString, 0
Sleep 3000
I = I + 1
End If
Next Atmt
Next Item
On Error GoTo ThisMacro_err
' Show this message when Finished
If I > 0 Then
MsgBox "De bestanden in de bijlage zijn opgeslagen op onderstaande locatie: " _
& DestFolder, vbInformation, "Klaar!"
Else
MsgBox "Er bevonden zich geen bijlagen bij de emails", vbInformation, "Klaar!"
End If
' Clear memory
ThisMacro_exit:
Set SubFolder = Nothing
Set Inbox = Nothing
Set ns = Nothing
Set fs = Nothing
Set wsh = Nothing
Set xlApp = Nothing
Set myBook = Nothing
Set AcroExchApp = Nothing
Set AcroExchAVDoc = Nothing
Exit Sub
' Error information
ThisMacro_err:
MsgBox "An unexpected error has occurred." _
& vbCrLf & "Please note and report the following information." _
& vbCrLf & "Macro Name: SaveEmailAttachmentsToFolder" _
& vbCrLf & "Error Number: " & Err.Number _
& vbCrLf & "Error Description: " & Err.Description _
, vbCritical, "Error!"
Resume ThisMacro_exit
End Sub
The WshShell object provides the Run method which has the bWaitOnReturn optional parameter. It indicates whether the script should wait for the program to finish executing before continuing to the next statement in your script. If set to true, script execution halts until the program finishes, and Run returns any error code returned by the program. If set to false (the default), the Run method returns immediately after starting the program, automatically returning 0 (not to be interpreted as an error code).
I currently have a macro that checks a folder for excel files and runs a few formatting type adjustments (adds columns etc).
The problem is that it will only allow me to select one folder and check in there. There are lots of folders that I need it to check in which all exist within the same directory.
I cannot select more than one folder to check in, even by adjusting the AllowMultiSelect to True. How can I modify this code so that it will allow me to select all folders within a directory?
Sub Button1_Click()
Dim wb As Workbook
Dim myPath As String
Dim myFile As String
Dim myExtension As String
Dim FldrPicker As FileDialog
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With FldrPicker
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo NextCode
myPath = .SelectedItems(1) & "\"
End With
NextCode:
myPath = myPath
If myPath = "" Then GoTo ResetSettings
myExtension = "*.xls"
myFile = Dir(myPath & myExtension)
Do While myFile <> ""
Set wb = Workbooks.Open(fileName:=myPath & myFile)
DoEvents
'Formatting adjustments etc go here
wb.Close SaveChanges:=True
DoEvents
myFile = Dir
Loop
MsgBox "Complete."
End Sub
I think I come up with some better solution than manually selecting all the folders. You said that all of your files are in some directory, which have some subfolders inside. With below code, you will loop through every file in folder you pick. You will store every formating logics in Formatting sub.
Sub Button1_Click()
Dim objFolder As Object
Dim objFile As Object
Dim objFSO As Object
Dim MyPath As String
Dim myExtension As String
Dim FldrPicker As FileDialog
Set FldrPicker = Application.FileDialog(msoFileDialogFolderPicker)
With FldrPicker
.Title = "Select A Target Folder"
.AllowMultiSelect = False
If .Show <> -1 Then GoTo NextCode
MyPath = .SelectedItems(1)
End With
Set objFSO = CreateObject("Scripting.FileSystemObject")
Call GetAllFiles(MyPath, objFSO)
Call GetAllFolders(MyPath, objFSO)
MsgBox "Complete."
NextCode:
End Sub
Sub GetAllFiles(ByVal strPath As String, ByRef objFSO As Object)
Dim objFolder As Object
Dim objFile As Object
Set objFolder = objFSO.GetFolder(strPath)
For Each objFile In objFolder.Files
Formatting (objFile.Path)
Next objFile
End Sub
Sub GetAllFolders(ByVal strFolder As String, ByRef objFSO As Object)
Dim objFolder As Object
Dim objSubFolder As Object
Set objFolder = objFSO.GetFolder(strFolder)
For Each objSubFolder In objFolder.subfolders
Call GetAllFiles(objSubFolder.Path, objFSO)
Call GetAllFolders(objSubFolder.Path, objFSO)
Next objSubFolder
End Sub
Sub Formatting(strFile As String)
Dim wb As Workbook
If Right(strFile, 3) = "xls" Then
Set wb = Workbooks.Open(Filename:=MyPath & myFile)
DoEvents
'Formatting adjustments etc go here
wb.Close SaveChanges:=True
DoEvents
myFile = Dir
End If
End Sub
How about this concept? You recursively map to all files in all folders, and create a schema of your whole folder structure. Then, control each file, based on each folder path.
Option Explicit
Sub ListAllFiles()
searchForFiles "C:\your_path_here\", "writefilestosheet", "*.*", True, True
End Sub
Sub processOneFile(ByVal aFilename As String)
Debug.Print aFilename
End Sub
Sub writeFilesToSheet(ByVal aFilename As String)
With ActiveSheet
.Cells(.Rows.Count, 1).End(xlUp).Offset(1, 0).Value = aFilename
End With
End Sub
Private Sub processFiles(ByVal DirToSearch As String, _
ByVal ProcToCall As String, _
ByVal FileTypeToFind As String)
Dim aFile As String
aFile = Dir(DirToSearch & FileTypeToFind)
Do While aFile <> ""
Application.Run ProcToCall, DirToSearch & aFile
aFile = Dir()
Loop
End Sub
Private Sub processSubFolders(ByVal DirToSearch As String, _
ByVal ProcToCall As String, _
ByVal FileTypeToFind As String, _
ByVal SearchSubDir As Boolean, _
ByVal FilesFirst As Boolean)
Dim aFolder As String, SubFolders() As String
ReDim SubFolders(0)
aFolder = Dir(DirToSearch, vbDirectory)
Do While aFolder <> ""
If aFolder <> "." And aFolder <> ".." Then
If (GetAttr(DirToSearch & aFolder) And vbDirectory) _
= vbDirectory Then
SubFolders(UBound(SubFolders)) = aFolder
ReDim Preserve SubFolders(UBound(SubFolders) + 1)
End If
End If
aFolder = Dir()
Loop
If UBound(SubFolders) <> LBound(SubFolders) Then
Dim i As Long
For i = LBound(SubFolders) To UBound(SubFolders) - 1
searchForFiles _
DirToSearch & SubFolders(i), _
ProcToCall, FileTypeToFind, SearchSubDir, FilesFirst
Next i
End If
End Sub
Sub searchForFiles(ByVal DirToSearch As String, ByVal ProcToCall As String, _
Optional ByVal FileTypeToFind As String = "*.*", _
Optional ByVal SearchSubDir As Boolean = False, _
Optional ByVal FilesFirst As Boolean = False)
On Error GoTo ErrXIT
If Right(DirToSearch, 1) <> Application.PathSeparator Then _
DirToSearch = DirToSearch & Application.PathSeparator
If FilesFirst Then processFiles DirToSearch, ProcToCall, FileTypeToFind
If SearchSubDir Then processSubFolders DirToSearch, ProcToCall, _
FileTypeToFind, SearchSubDir, FilesFirst
If Not FilesFirst Then _
processFiles DirToSearch, ProcToCall, FileTypeToFind
Exit Sub
ErrXIT:
MsgBox "Fatal error: " & Err.Description & " (Code=" & Err.Number & ")"
Exit Sub
End Sub
I want to connect csv files with excels power pivot with a VBA code by using WorkbookConnection.AddfromFile
My question:
I want to connect numerous csv file. To do so I have to click for hours through the Text Import Wizard. I haven't found out yet how to automatize this! I imagine to do it in a similar way like I did it with the FileDialog in the upper part of my code. Below the part of my code where I want to implement it.
For LoopCounter = 1 To fd.SelectedItems.count
ActiveWorkbook.Connections.AddFromFile _
fd.SelectedItems(LoopCounter), True, False
Next LoopCounter
Below the code I have already written. With this code I have to click through the TextImportWizard manually.
Sub csv()
Dim fd As FileDialog
Dim ActionClicked As Boolean
Dim LoopCounter As Long
Set fd = Application.FileDialog(msoFileDialogFilePicker)
fd.InitialFileName = "C:\temp"
fd.AllowMultiSelect = True
fd.Title = "Open your data"
fd.ButtonName = "GO"
ActionClicked = fd.Show
If ActionClicked Then
For LoopCounter = 1 To fd.SelectedItems.count
ActiveWorkbook.Connections.AddFromFile _
fd.SelectedItems(LoopCounter), True, False
Next LoopCounter
Else
MsgBox "You didn't choose anything"
Exit Sub
End If
End Sub
The faster way to import CSV or text files is with the following
Dim InputStringCSV As String
Dim CSVFile As Variant
Dim ArrayStringCSV() As String
CSVFile = Application.GetOpenFilename("CSV Files,*.CSV", Title:="MyData")
If CSVFile = False Then "No input!", vbCritical: End
Open CSVFile For Input As #1
Do Until EOF(1)
Line Input #1, InputStringCSV
ArrayStringCSV = Split(InputStringCSV, Chr(10))
For CounterArray = LBound(ArrayStringCSV) To UBound(ArrayStringCSV)
'Defaults: Row 1 is the beginnning for the sheet
Sheets(Sheet_CSV).Cells(1 + CounterArray, 1).NumberFormat = "#"
Sheets(Sheet_CSV).Cells(1 + CounterArray, 1) = ArrayStringCSV(CounterArray)
Next CounterArray
Loop
Close #1
If you want to automate it for all the CSV files in a folder, I'd suggest that you loop through archives -looking for .csv ones-, here's a sample on how to get you started:
Set oFSO = CreateObject("Scripting.FileSystemObject")
oStartFolder = "C:/Documents"
Set oFolder = oFSO.GetFolder(oStartFolder)
oFSO.GetFolder (oFolder)
For Each FileItem In oFolder.Files
if Instr(FileItem,".csv") Then Call ImportCSV(FileName) 'you would change the above code to don't ask folder and set the argument so each time you call it would be the file csv in the folder
Next FileItem
There are lots of ways to import text files. See the link below.
http://www.rondebruin.nl/win/s3/win022.htm
This AddIn will do the work for you.
http://www.rondebruin.nl/win/addins/rdbmerge.htm
Also, you can merge all your text files in a folder into one worksheet.
Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32" _
(ByVal hProcess As Long, _
lpExitCode As Long) As Long
#Else
Private Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" _
(ByVal hProcess As Long, _
lpExitCode As Long) As Long
#End If
Public Const PROCESS_QUERY_INFORMATION = &H400
Public Const STILL_ACTIVE = &H103
Public Sub ShellAndWait(ByVal PathName As String, Optional WindowState)
Dim hProg As Long
Dim hProcess As Long, ExitCode As Long
'fill in the missing parameter and execute the program
If IsMissing(WindowState) Then WindowState = 1
hProg = Shell(PathName, WindowState)
'hProg is a "process ID under Win32. To get the process handle:
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, hProg)
Do
'populate Exitcode variable
GetExitCodeProcess hProcess, ExitCode
DoEvents
Loop While ExitCode = STILL_ACTIVE
End Sub
Sub Merge_CSV_Files()
Dim BatFileName As String
Dim TXTFileName As String
Dim XLSFileName As String
Dim FileExtStr As String
Dim FileFormatNum As Long
Dim DefPath As String
Dim Wb As Workbook
Dim oApp As Object
Dim oFolder
Dim foldername
'Create two temporary file names
BatFileName = Environ("Temp") & _
"\CollectCSVData" & Format(Now, "dd-mm-yy-h-mm-ss") & ".bat"
TXTFileName = Environ("Temp") & _
"\AllCSV" & Format(Now, "dd-mm-yy-h-mm-ss") & ".txt"
'Folder where you want to save the Excel file
DefPath = Application.DefaultFilePath
If Right(DefPath, 1) <> "\" Then
DefPath = DefPath & "\"
End If
'Set the extension and file format
If Val(Application.Version) < 12 Then
'You use Excel 97-2003
FileExtStr = ".xls": FileFormatNum = -4143
Else
'You use Excel 2007 or higher
FileExtStr = ".xlsx": FileFormatNum = 51
'If you want to save as xls(97-2003 format) in 2007 use
'FileExtStr = ".xls": FileFormatNum = 56
End If
'Name of the Excel file with a date/time stamp
XLSFileName = DefPath & "MasterCSV " & _
Format(Now, "dd-mmm-yyyy h-mm-ss") & FileExtStr
'Browse to the folder with CSV files
Set oApp = CreateObject("Shell.Application")
Set oFolder = oApp.BrowseForFolder(0, "Select folder with CSV files", 512)
If Not oFolder Is Nothing Then
foldername = oFolder.Self.Path
If Right(foldername, 1) <> "\" Then
foldername = foldername & "\"
End If
'Create the bat file
Open BatFileName For Output As #1
Print #1, "Copy " & Chr(34) & foldername & "*.csv" _
& Chr(34) & " " & TXTFileName
Close #1
'Run the Bat file to collect all data from the CSV files into a TXT file
ShellAndWait BatFileName, 0
If Dir(TXTFileName) = "" Then
MsgBox "There are no csv files in this folder"
Kill BatFileName
Exit Sub
End If
'Open the TXT file in Excel
Application.ScreenUpdating = False
Workbooks.OpenText Filename:=TXTFileName, Origin:=xlWindows, StartRow _
:=1, DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, Tab:=False, Semicolon:=False, Comma:=True, _
Space:=False, Other:=False
'Save text file as a Excel file
Set Wb = ActiveWorkbook
Application.DisplayAlerts = False
Wb.SaveAs Filename:=XLSFileName, FileFormat:=FileFormatNum
Application.DisplayAlerts = True
Wb.Close savechanges:=False
MsgBox "You find the Excel file here: " & vbNewLine & XLSFileName
'Delete the bat and text file you temporary used
Kill BatFileName
Kill TXTFileName
Application.ScreenUpdating = True
End If
End Sub
You'll find more info here.
http://www.rondebruin.nl/win/s3/win021.htm
If you want to maintain the data connections, like I do, then you need to first make a query using Power Query M formula. Then you can add your connection to that query. This is what Excel does when you use the Get Data wizards.
Use this procedure in your loop and it will make a new sheet for each CSV file:
'#Description("Create a new worksheet with a table that is connected to a CSV file as a data source.")
Public Sub GetDataFromCSV(ByVal name As String, ByVal fileName As String)
On Error GoTo errorHandler
' The Power Query points to the CSV file, if your data contains headers you need the Promoted Headers
Dim csvFormula As String
csvFormula = "let" & vbNewLine & _
" Source = Csv.Document(File.Contents(""" & fileName & """),null,null,null,1252)," & vbNewLine & _
" #""Promoted Headers"" = Table.PromoteHeaders(Source, [PromoteAllScalars=true])" & vbNewLine & _
"in" & vbNewLine & _
" #""Promoted Headers"""
ThisWorkbook.Queries.Add name:=name, Formula:=csvFormula
' The workbook connects to that query
Dim newConnection As WorkbookConnection
Set newConnection = ThisWorkbook.Connections.Add2("Query - " & name, _
"Connection to the '" & name & "' query in the workbook.", _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & name & ";Extended Properties="""";", """" & name & """", 6, True, False)
' I always want one table per sheet that begins at A1
Dim newSheet As Worksheet
Set newSheet = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
newSheet.name = name
' Only once you have the connection backed by the query can you link it to a Table
With newSheet.ListObjects.Add(SourceType:=xlSrcModel, Source:=newConnection, LinkSource:=True, XlListObjectHasHeaders:=xlYes, Destination:=newSheet.Range("$A$1")).TableObject
.RowNumbers = False
.PreserveFormatting = True
.RefreshStyle = 1
.AdjustColumnWidth = True
' I get errors when there are hyphens in the DisplayName, the default behavior of the wizard replaces them with underscors
.ListObject.DisplayName = Replace(name, "-", "_")
.Refresh
End With
Exit Sub
errorHandler:
If Err.Number = -2147024809 Then
' Query already exists, we delete it so we can recreate it
ThisWorkbook.Queries.Item(name).Delete
Resume
Else
Debug.Print "ERROR " & Err.Number & " : " & Err.Description
End If
End Sub
With my code I have to write a file name to search : "test.txt" . It works fine, returns as many as test.txt exist in the selected path.
I want it to work searching : "txt" and get all the .txt files in the selected path.
My code :
Option Explicit
Dim fso As New FileSystemObject
Dim fld As Folder
Private Sub Command1_Click()
Dim nDirs As Long, nFiles As Long, lSize As Currency
Dim sDir As String, sSrchString As String
sDir = InputBox("Type the directory that you want to search for", _
"FileSystemObjects example", "C:\")
sSrchString = InputBox("Type the file name that you want to search for", _
"FileSystemObjects example", "")
' MousePointer = vbHourglass
' Label1.Caption = "Searching " & vbCrLf & UCase(sDir) & "..."
lSize = FindFile(sDir, sSrchString, nDirs, nFiles)
' MousePointer = vbDefault
MsgBox Str(nFiles) & " files found in" & Str(nDirs) & _
" directories", vbInformation
MsgBox "Total Size = " & lSize & " bytes"
End Sub
Private Function FindFile(ByVal sFol As String, sFile As String, _
nDirs As Long, nFiles As Long) As Currency
Dim tFld As Folder, tFil As File, FileName As String
On Error GoTo Catch
Set fld = fso.GetFolder(sFol)
FileName = Dir(fso.BuildPath(fld.path, sFile), vbNormal Or _
vbHidden Or vbSystem Or vbReadOnly)
While Len(FileName) <> 0
FindFile = FindFile + FileLen(fso.BuildPath(fld.path, _
FileName))
nFiles = nFiles + 1
' List1.AddItem fso.BuildPath(fld.Path, FileName) ' Load ListBox
FileName = Dir() ' Get next file
DoEvents
Wend
' Label1 = "Searching " & vbCrLf & fld.Path & "..."
nDirs = nDirs + 1
If fld.SubFolders.Count > 0 Then
For Each tFld In fld.SubFolders
DoEvents
FindFile = FindFile + FindFile(tFld.Path, sFile, nDirs, nFiles)
Next
End If
Exit Function
Catch: FileName = ""
Resume Next
End Function
and a tip, I've found something like :
For Each file In files
If Right(file, 3) = "pdf" Then
myMailItem.Attachments.Add CStr(file)
found = True
End If
But I couldn't get it working in my code.
Thanks!