Access VBA to delete a file to the recycle bin? - vba

Using the following code delete's my file, but it doesn't go to the recycle bin - does code exist that will send it to the recycle bin? Should I use ".Move" ?
If MsgBox("DELETE:" & Chr(10) & Forms("frmtbl").f_FullPath & Me.f_FileName & " ?", vbYesNo) = vbYes Then
'Kill Forms("frmtbl").f_FullPath & Me.f_FileName
Dim objFSO As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.DeleteFile (Forms("frmtbl").f_FullPath & Me.f_FileName)
DoCmd.Close acForm, Me.Name
Else
MsgBox "FILE NOT DELETED:" & Chr(10) & Forms("frmtbl").f_FullPath & Me.f_FileName & ".", vbInformation,
End If
.MoveFile to the recycle bin requires permissions I don't have.

An integrated VBA-method seems not to exist. API call is needed.
Following code is copied from reddit. (solution by "Crushnaut")
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Windows API functions, constants,and types.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Declare PtrSafe Function SHFileOperation Lib "shell32.dll" Alias _
"SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As LongPtr
Private Const FO_DELETE = &H3
Private Const FOF_ALLOWUNDO = &H40
Private Const FOF_NOCONFIRMATION = &H10
Private Type SHFILEOPSTRUCT
hwnd As LongPtr
wFunc As LongPtr
pFrom As String
pTo As String
fFlags As Integer
fAnyOperationsAborted As Boolean
hNameMappings As LongPtr
lpszProgressTitle As String
End Type
Public Function Recycle(FileSpec As String, Optional ErrText As String) As Boolean
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Recycle
' This function sends FileSpec to the Recycle Bin. There
' are no restriction on what can be recycled. FileSpec
' must be a fully qualified folder or file name on the
' local machine.
' The function returns True if successful or False if
' an error occurs. If an error occurs, the reason for the
' error is placed in the ErrText varaible.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim SHFileOp As SHFILEOPSTRUCT
Dim Res As LongPtr
Dim sFileSpec As String
ErrText = vbNullString
sFileSpec = FileSpec
If InStr(1, FileSpec, ":", vbBinaryCompare) = 0 Then
''''''''''''''''''''''''''''''''''''''
' Not a fully qualified name. Get out.
''''''''''''''''''''''''''''''''''''''
ErrText = "'" & FileSpec & "' is not a fully qualified name on the local machine"
Recycle = False
Exit Function
End If
If Dir(FileSpec, vbDirectory) = vbNullString Then
ErrText = "'" & FileSpec & "' does not exist"
Recycle = False
Exit Function
End If
''''''''''''''''''''''''''''''''''''
' Remove trailing '\' if required.
''''''''''''''''''''''''''''''''''''
If Right(sFileSpec, 1) = "\" Then
sFileSpec = Left(sFileSpec, Len(sFileSpec) - 1)
End If
With SHFileOp
.wFunc = FO_DELETE
.pFrom = sFileSpec
.fFlags = FOF_ALLOWUNDO
'''''''''''''''''''''''''''''''''
' If you want to supress the
' "Are you sure?" message, use
' the following:
'''''''''''''''''''''''''''''''
.fFlags = FOF_ALLOWUNDO + FOF_NOCONFIRMATION
End With
Res = SHFileOperation(SHFileOp)
If Res = 0 Then
Recycle = True
Else
Recycle = False
End If
End Function

Related

Why does my Access database object variable lose connection to its source file midway through reading its Modules container?

We use a VBA tool to extract modules, forms and reports from our Access applications and create an executable for users. This tool has been working without any problems until very recently. However, when I use it to extract from a couple of applications, I keep on encountering an "Automation Error (The remote procedure call failed)" error. However, my colleague (running the same code on a virtually identical build) is able to run it ok.
This is running on Win10 Pro (v2004 - 19041.685), Office 2016 Pro Plus (16.0.4266.1001). I believe my colleague's machine should be the same, as we have only just moved across to these laptops.
This is the core code:
Public Sub ExportAll()
On Error GoTo ErrorProc
Dim oAccessApp As Access.Application
Dim oDoc As Document
Dim sFilePath As String
Dim oDb As Database
Dim fso As FileSystemObject
Dim strFile As String
Dim strFolder As String
strFile = "accdb path"
strFolder = oApp.GetFolder(strFile)
Set oAccessApp = oApp.OpenDatabase(strFile)
Set oDb = oAccessApp.CurrentDb
Set fso = New FileSystemObject
If Not fso.FolderExists((strFolder) & "\SCC") Then
fso.CreateFolder strFolder & "\SCC"
End If
If Not fso.FolderExists(strFolder & "\SCC\Modules") Then
fso.CreateFolder strFolder & "\SCC\Modules"
End If
If Not fso.FolderExists(strFolder & "\SCC\Forms") Then
fso.CreateFolder strFolder & "\SCC\Forms"
End If
If Not fso.FolderExists(strFolder & "\SCC\Reports") Then
fso.CreateFolder strFolder & "\SCC\Reports"
End If
For Each oDoc In oDb.Containers("Modules").Documents
DoEvents
sFilePath = strFolder & "\SCC\Modules\" & oDoc.Name & ".bas.txt"
oAccessApp.SaveAsText acModule, oDoc.Name, sFilePath
Next
For Each oDoc In oDb.Containers("Forms").Documents
DoEvents
sFilePath = strFolder & "\SCC\Forms\" & oDoc.Name & ".frm.txt"
oAccessApp.SaveAsText acForm, oDoc.Name, sFilePath
Next
For Each oDoc In oDb.Containers("Reports").Documents
DoEvents
sFilePath = strFolder & "\SCC\Reports\" & oDoc.Name & ".rpt.txt"
oAccessApp.SaveAsText acReport, oDoc.Name, sFilePath
Next
oDb.Close
Set oDb = Nothing
oAccessApp.Quit
Set oAccessApp = Nothing
Exit Sub
ErrorProc:
If Not (oAccessApp Is Nothing) Then
oAccessApp.Quit
End If
Set oAccessApp = Nothing
MsgBox Err.Description, vbExclamation, "Error " & Err.Number
End Sub
As the extraction takes place, the database being extracted should remain open throughout. Each failure occurs in the For Each oDoc In oDb.Containers("Modules").Documents loop, and happens when a particular module is referenced by the oDoc variable. When I step through and reach the offending module, all is fine until the line with oDoc.Name is hit, at which point the database closes and all the messages for the object oDb reads "".
The module causing the problem is below:
Option Compare Database
Option Explicit
'
' Opens file using default program
' (.xls files open in Excel, .doc files open in Word, etc)
'
'Code Courtesy of
'Dev Ashish
#If Win64 Then
Private Declare PtrSafe Function apiShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hWnd As LongPtr, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As LongPtr
#Else
Private Declare Function apiShellExecute 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
#End If
Public Enum ShellExecuteWinStyle
WIN_NORMAL = 1 'Open Normal
WIN_MAX = 2 'Open Maximized
WIN_MIN = 3 'Open Minimized
End Enum
Private Const ERROR_SUCCESS = 32&
Private Const ERROR_NO_ASSOC = 31&
Private Const ERROR_OUT_OF_MEM = 0&
Private Const ERROR_FILE_NOT_FOUND = 2&
Private Const ERROR_PATH_NOT_FOUND = 3&
Private Const ERROR_BAD_FORMAT = 11&
'
' Opens file using default program
' (.xls files open in Excel, .doc files open in Word, etc)
'
Function ShellExecute(strFile As Variant, lShowHow As ShellExecuteWinStyle)
#If Win64 Then
Dim lRet As LongPtr
#Else
Dim lRet As Long
#End If
Dim varTaskID As Variant
Dim stRet As String
Dim stFile As String
If IsNull(strFile) Or strFile = "" Then Exit Function
stFile = strFile
'First try ShellExecute
lRet = apiShellExecute(hWndAccessApp, vbNullString, _
stFile, vbNullString, vbNullString, lShowHow)
If lRet > ERROR_SUCCESS Then
stRet = vbNullString
lRet = -1
Else
Select Case lRet
Case ERROR_NO_ASSOC:
'Try the OpenWith dialog
varTaskID = Shell("rundll32.exe shell32.dll,OpenAs_RunDLL " _
& stFile, WIN_NORMAL)
lRet = (varTaskID <> 0)
Case ERROR_OUT_OF_MEM:
stRet = "Error: Out of Memory/Resources. Couldn't Execute!"
Case ERROR_FILE_NOT_FOUND:
stRet = "Error: File not found. Couldn't Execute!"
Case ERROR_PATH_NOT_FOUND:
stRet = "Error: Path not found. Couldn't Execute!"
Case ERROR_BAD_FORMAT:
stRet = "Error: Bad File Format. Couldn't Execute!"
Case Else:
End Select
End If
ShellExecute = lRet & _
IIf(stRet = "", vbNullString, ", " & stRet)
End Function
I have tried the following:
removing the problem module (process completes successfully)
renaming the module
removing pro-compile conditional statements
moving extraction code to a new database
extracting from database with only problem module plus module with comments
repair MS Office
reinstall MS Office
downgrade Windows updates
Does anyone have any idea why this might be failing? Any suggestions on how to rectify would be really appreciated.

AutoCAD VBA to Launch FileDialog with Windows API throws Error 449 "Argument Not Optional"

I have a custom VBA program that loops through a bunch of AutoCAD files and extracts data from them. As of right now I'm using a separate Excel file to select multiple .dwg files via Excel FileDialog and I'd like to have that file selection be done in AutoCAD instead.
I've found an API Function on an AutoCAD help forum but can't get it to work. It's titled "FileDialogs."
The first block of code is my primary module, the second block is the FileDialogs class module I was given.
I've gone through the FileDialogs Class Module that references the Windows API and added "PtrSafe" to the functions and changed all the "Long"s to "LongPtr."
-EDIT-
I've updated the code to my semi-working code. It launches a file window but doesn't return a list of selected drawings, so, idk. Good 'nuff?
'THIS IS MY PRIMARY MODULE
Public Sub OpenFile()
Set objFile = New FileDialogs
Dim initpath As String
Dim initfilter As String
Dim inittitle As String
initpath = ThisDrawing.Path & "\"
'initfilter = "Drawing Files (*.dwg)|*.dwg"
inittitle = "Select Files"
'objFile.OwnerHwnd = ThisDrawing.Hwnd
'objFile.title = "Select Drawings"
objFile.MultiSelect = True
'objFile.Filter = initfilter
'objFile.StartInDir = initpath
strFileName = objFile.ShowOpen(initpath, initfilter, inittitle)
If Not strFileName = vbNullString Then
MsgBox strFileName
End If
Set objFile = Nothing
End Sub
'THIS IS THE CLASS MODULE I WAS GIVEN ON THE AUTOCAD FORUM
Option Explicit
'//The Win32 API Functions///
Private Declare PtrSafe Function GetOpenFileName Lib "comdlg32.dll" _
Alias "GetOpenFileNameA" (OFN As OPENFILENAME) As Boolean
Private Declare PtrSafe Function GetSaveFileName Lib "comdlg32.dll" _
Alias "GetSaveFileNameA" (OFN As OPENFILENAME) As Boolean
Private Declare PtrSafe Function FindWindow Lib "user32" _
Alias "FindWindowA" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As LongPtr
'//A few of the available Flags///
Private Const OFN_FILEMUSTEXIST = &H1000
Private Const OFN_HIDEREADONLY = &H4
Private Const OFN_ALLOWMULTISELECT = &H200
'This one keeps your dialog from turning into
'A browse by folder dialog if multiselect is true!
'Not sure what I mean? Remove it from the flags
'In the "ShowOpen Open" & "ShowOpen Save" methods.
Private Const OFN_EXPLORER As Long = &H80000
'//The Structure
Private Type OPENFILENAME
lStructSize As Long
hwndOwner As LongPtr
hInstance As LongPtr
lpstrFilter As String
lpstrCustomFilter As String
nMaxCustFilter As Long
nFilterIndex As Long
lpstrFile As String
nMaxFile As Long
lpstrFileTitle As String
nMaxFileTitle As Long
lpstrInitialDir As String
lpstrTitle As String
flags As Long
nFileOffset As Integer
nFileExtension As Integer
lpstrDefExt As String
lCustData As Long
lpfnHook As LongPtr
lpTemplateName As String
End Type
Private lngHwnd As LongPtr
Public strFilter As String
Public strTitle As String
Public strDir As String
Private blnHideReadOnly As Boolean
Private blnAllowMulti As Boolean
Private blnMustExist As Boolean
Private Sub Class_Initialize()
'Set default values when
'class is first created
strDir = Application.ActiveDocument.Path & "\"
strTitle = "Select Files"
'strFilter = "Drawing Files" & Chr$(0) & "*.dwg" & Chr$(0)
lngHwnd = FindWindow(vbNullString, Application.Caption)
'None of the flags are set here!
End Sub
Public Function FindUserForm(objForm As UserForm) As LongPtr
Dim lngTemp As LongPtr
Dim strCaption As String
strCaption = objForm.Caption
lngTemp = FindWindow(vbNullString, strCaption)
If lngTemp <> 0 Then
FindUserForm = lngTemp
End If
End Function
Public Property Let OwnerHwnd(ByVal WindowHandle As LongPtr)
'//FOR YOU TODO//
'Use the API to validate this handle
lngHwnd = WindowHandle
'This value is set at startup to the handle of the
'AutoCAD Application window, if you want the owner
'to be a user form you will need to obtain its
'Handle by using the "FindUserForm" function in
'This class.
End Property
Public Property Get OwnerHwnd() As LongPtr
OwnerHwnd = lngHwnd
End Property
Public Property Let title(ByVal Caption As String)
'strTitle = "Select Files"
End Property
Public Property Get title() As String
'title = strTitle
End Property
Public Property Let Filter(ByVal FilterString As String)
'Filters change the type of files that are
'displayed in the dialog. I have designed this
'validation to use the same filter format the
'Common dialog OCX uses:
'"All Files (*.*)|*.*"
Dim intPos As Integer
Do While InStr(FilterString, "|") > 0
intPos = InStr(FilterString, "|")
If intPos > 0 Then
FilterString = Left$(FilterString, intPos - 1) _
& Chr$(0) & Right$(FilterString, _
Len(FilterString) - intPos)
End If
Loop
If Right$(FilterString, 2) <> Chr$(0) & Chr$(0) Then
FilterString = FilterString & Chr$(0)
End If
'strFilter = FilterString
End Property
Public Property Get Filter() As String
'Here we reverse the process and return
'the Filter in the same format the it was
'entered
Dim intPos As Integer
Dim strTemp As String
strTemp = strFilter
Do While InStr(strTemp, Chr$(0)) > 0
intPos = InStr(strTemp, Chr$(0))
If intPos > 0 Then
strTemp = Left$(strTemp, intPos - 1) & "|" & Right$(strTemp, _
Len(strTemp) - intPos)
End If
Loop
If Right$(strTemp, 1) = "|" Then
strTemp = Left$(strTemp, Len(strTemp) - 1)
End If
Filter = strTemp
End Property
Public Property Let StartInDir(ByVal strFolder As String)
'Sets the directory the dialog displays when called
If Len(Dir(strFolder)) > 0 Then
strDir = strFolder
Else
Err.Raise 514, "FileDialog", "Invalid Initial Directory"
End If
End Property
Public Property Let HideReadOnly(ByVal blnVal As Boolean)
blnHideReadOnly = blnVal
End Property
Public Property Let MultiSelect(ByVal blnVal As Boolean)
'allow users to select more than one file using
'The Shift or CTRL keys during selection
blnAllowMulti = True
End Property
Public Property Let FileMustExist(ByVal blnVal As Boolean)
blnMustExist = blnVal
End Property
'#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
' Display and use the File open dialog
'#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
Function thAddFilterItem(ByVal strFilter As String, ByVal strDescription As String, Optional ByVal varItem As Variant) As String
If IsMissing(varItem) Then varItem = "*.*"
thAddFilterItem = strFilter & strDescription & vbNullChar & varItem & vbNullChar
End Function
Public Function ShowOpen(ByVal strDir As String, ByVal strFilter As String, ByVal strTitle As String) As String
Dim strTemp As String
'strFilter = thAddFilterItem(strFilter, "Drawing Files (*.dwg)", "*.dwg")
Dim udtStruct As OPENFILENAME
With udtStruct
.lStructSize = LenB(udtStruct)
'Use our private variable
.hwndOwner = lngHwnd
'Use our private variable
.lpstrFilter = strFilter
.lpstrFile = Space$(254)
.nMaxFile = 255
.lpstrFileTitle = Space$(254)
.nMaxFileTitle = 255
'Use our private variable
.lpstrInitialDir = strDir
'Use our private variable
.lpstrTitle = strTitle
' udtStruct.lpstrCustomFilter = "*.*"
'Ok, here we test our booleans to
'set the flag
End With
If blnHideReadOnly And blnAllowMulti And blnMustExist Then
udtStruct.flags = OFN_HIDEREADONLY Or _
OFN_ALLOWMULTISELECT Or OFN_EXPLORER Or OFN_FILEMUSTEXIST
ElseIf blnHideReadOnly And blnAllowMulti Then
udtStruct.flags = OFN_ALLOWMULTISELECT _
Or OFN_EXPLORER Or OFN_HIDEREADONLY
ElseIf blnHideReadOnly And blnMustExist Then
udtStruct.flags = OFN_HIDEREADONLY Or OFN_FILEMUSTEXIST
ElseIf blnAllowMulti And blnMustExist Then
udtStruct.flags = OFN_ALLOWMULTISELECT Or _
OFN_EXPLORER Or OFN_FILEMUSTEXIST
ElseIf blnHideReadOnly Then
udtStruct.flags = OFN_HIDEREADONLY
ElseIf blnAllowMulti Then
udtStruct.flags = OFN_ALLOWMULTISELECT _
Or OFN_EXPLORER
ElseIf blnMustExist Then
udtStruct.flags = OFN_FILEMUSTEXIST
End If
If GetOpenFileName(udtStruct) Then
strTemp = (Trim(udtStruct.lpstrFile))
ShowOpen = Mid(strTemp, 1, Len(strTemp) - 1)
End If
End Function
'#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
' Display and use the File Save dialog
'#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
Public Function ShowSave(ByVal strDir As String, ByVal strFilter, ByVal strTitle) As String
Dim strTemp As String
Dim udtStruct As OPENFILENAME
udtStruct.lStructSize = LenB(udtStruct)
'Use our private variable
udtStruct.hwndOwner = lngHwnd
'Use our private variable
udtStruct.lpstrFilter = strFilter
udtStruct.lpstrFile = Space$(254)
udtStruct.nMaxFile = 255
udtStruct.lpstrFileTitle = Space$(254)
udtStruct.nMaxFileTitle = 255
'Use our private variable
udtStruct.lpstrInitialDir = strDir
'Use our private variable
udtStruct.lpstrTitle = strTitle
If blnMustExist Then
udtStruct.flags = OFN_FILEMUSTEXIST
End If
If GetSaveFileName(udtStruct) Then
strTemp = (Trim(udtStruct.lpstrFile))
ShowSave = Mid(strTemp, 1, Len(strTemp) - 1)
End If
End Function
Function GetXLSFile(ByVal strDir As String, ByVal strTitle As String)
' strTitle = "Select Excel File"
Dim strFilter As String ' , strTitle As String
Dim lngFlags As LongPtr, filestring
strFilter = thAddFilterItem(strFilter, "Excel File (*.xls)", "*.xls")
GetXLSFile = ShowOpen(strDir, strFilter, strTitle)
End Function
Function GetDWGFile(ByVal strDir As String, ByVal strTitle As String)
' strTitle = "Select Drawing File"
Dim strFilter As String ' , strTitle As String
Dim lngFlags As LongPtr, filestring
strFilter = thAddFilterItem(strFilter, "DWG File (*.dwg)", "*.dwg")
GetDWGFile = ShowOpen(strDir, strFilter, strTitle)
End Function
Function SaveFile() '
Dim strTitle As String
Dim strDir As String
Dim strFilter As String ' , strTitle As String
Dim lngFlags As LongPtr, filestring
strDir = "c:\"
strTitle = "Save File"
strFilter = thAddFilterItem(strFilter, "txt File (*.txt)", "*.txt")
'SaveFile = ShowSave(strDir, strFilter, strTitle)
End Function

VBA create log file

Hello can you help me please with code in VBA ? I would like create a log file from text in cells ("C2" and "C3 " + date and time ) when I press button "zadat" Thank you
My code for implementation is:
Module 1
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub zadat()
Dim reg, check As String
Dim i, j, done As Integer
reg = Cells(2, 3).Value
check = Cells(4, 3).Value
If check = "True" Then
i = 2
j = 1
done = 0
Do While Sheets("data").Cells(i, j) <> ""
If Sheets("data").Cells(i, j) = reg Then
vytisteno = ZkontrolovatAVytiskoutSoubor()
done = Sheets("data").Cells(i, j + 3)
done = done + 1
Sheets("data").Cells(i, j + 3) = done
Exit Do
End If
i = i + 1
Loop
Else
MsgBox ("Opravit, špatný štítek!!!")
End If
Cells(3, 3) = ""
Cells(3, 3).Select
ActiveWindow.ScrollRow = Cells(1, 1).row
End Sub
Module 2:
Option Explicit
Public 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 Function PrintThisDoc(formname As Long, FileName As String)
On Error Resume Next
Dim x As Long
x = ShellExecute(formname, "Print", FileName, 0&, 0&, 3)
End Function
Public Function ZkontrolovatAVytiskoutSoubor() As Boolean
Dim printThis
Dim strDir As String
Dim strFile As String
strDir = "W:\Etikety\Štítky\Krabice\Testy"
strFile = Range("C2").Value & ".lbe"
If Not FileExists(strDir & "\" & strFile) Then
MsgBox "soubor neexistuje!"
ZkontrolovatAVytiskoutSoubor = False
Else
printThis = PrintThisDoc(0, strDir & "\" & strFile)
ZkontrolovatAVytiskoutSoubor = True
End If
End Function
Private Function FileExists(fname) As Boolean
'Returns TRUE if the file exists
Dim x As String
x = Dir(fname)
If x <> "" Then FileExists = True _
Else FileExists = False
End Function
If you don't want to use FSO, there is a simple solution using only VBA statements: Open, Print # and Close:
Sub Log2File(Filename As String, Cell1, Cell2)
Dim f As Integer
f = FreeFile
Open Filename For Append Access Write Lock Write As #f
Print #f, Now, Cell1, Cell2
Close #f
End Sub
I've put the filename and the cells refs as arguments of the sub for re-usability purpose. I also use default (local) formatting, but this can be easily changed.
Note that you don't have to check for existence of the file, it will be created if it doesn't exist.
Try this. Below code will create a new log file every time
Public Function LogDetails()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim logFile As Object
Dim logFilePath As String
Dim logFileName As String
'Replace 'TestLog' with your desired file name
logFileName = "TestLog" & ".txt"
myFilePath = "C:\Users\..\Desktop\" & logFileName 'Modify the path here
If fso.FileExists(myFilePath) Then
Set logFile = fso.OpenTextFile(myFilePath, 8)
Else
' create the file instead
Set logFile = fso.CreateTextFile(myFilePath, True)
End If
logFile.WriteLine "[" & Date & " " & Time & "] " & Worksheet("yoursheetnamehere").Cells(2, 3) & " " & Worksheet("yoursheetnamehere").Cells(3, 3)
logFile.Close ' close the file
End Function

How can I automate the addition from WorkbookConnections with VBA?

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

Why is this call to InvokeVerb ("&Print") not working?

I'm just trying to batch print a large amount of files from a folder. The folder contains multiple file types, and I just want to invoke the print method equivalent to Right-Click > Print.
It seems like I should be able to do this using the InvokeVerb method of Shell32.FolderItem object.
So, I can't figure out why, when I run the code below, nothing prints.
Any ideas?
( GetFolder is just a wrapper for the Shell32.BrowseForFolder function which returns the path to the folder selected. That function works without issue. For testing you can just replace with a path to a folder.)
Sub printFOO()
Dim shApp As Shell32.Shell
Dim srFSO As Scripting.FileSystemObject
Dim strPath As String
Dim shFIcol As Shell32.FolderItems
Dim shFIx As Shell32.FolderItem
Dim shFLDx As Shell32.Folder
Dim lngX As Long
Set shApp = New Shell32.Shell
Set srFSO = New Scripting.FileSystemObject
strPath = GetFolder("Choose a folder...")
Set shFLDx = shApp.NameSpace(strPath)
Set shFIcol = shFLDx.Items()
For Each shFIx In shFIcol
'For lngX = 0 To shFIx.Verbs.Count
'Debug.Print shFIx.Verbs.ITEM(lngX).Name
'Next
'msgbox("printing "&shFIx.name)
shFIx.InvokeVerb ("&Print")
DoEvents
Next
End Sub
Here's a program that does it using slightly different method. It also lists verbs available.
HelpMsg = vbcrlf & " ShVerb" & vbcrlf & vbcrlf & " David Candy 2014" & vbcrlf & vbcrlf & " Lists or runs an explorer verb (right click menu) on a file or folder" & vbcrlf & vbcrlf & " ShVerb <filename> [verb]" & vbcrlf & vbcrlf & " Used without a verb it lists the verbs available for the file or folder" & vbcrlf & vbcrlf
HelpMsg = HelpMsg & " The program lists most verbs but only ones above the first separator" & vbcrlf & " of the menu work when used this way" & vbcrlf & vbcrlf
HelpMsg = HelpMsg & " The Properties verb can be used. However the program has to keep running" & vbcrlf & " to hold the properties dialog open. It keeps running by displaying" & vbcrlf & " a message box."
Set objShell = CreateObject("Shell.Application")
Set Ag = WScript.Arguments
set WshShell = WScript.CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
If Ag.count = 0 then
wscript.echo " ShVerb - No file specified"
wscript.echo HelpMsg
wscript.quit
Else If Ag.count = 1 then
If LCase(Replace(Ag(0),"-", "/")) = "/h" or Replace(Ag(0),"-", "/") = "/?" then
wscript.echo HelpMsg
wscript.quit
End If
ElseIf Ag.count > 2 then
wscript.echo vbcrlf & " ShVerb - To many parameters" & vbcrlf & " Use quotes around filenames and verbs containing spaces" & vbcrlf
wscript.echo HelpMsg
wscript.quit
End If
If fso.DriveExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetFileName(Ag(0)))
' Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
Set objFolderItem = objFolder.self
msgbox ag(0)
ElseIf fso.FolderExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetParentFolderName(Ag(0)))
Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
ElseIf fso.fileExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetParentFolderName(Ag(0)))
Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
Else
wscript.echo " ShVerb - " & Ag(0) & " not found"
wscript.echo HelpMsg
wscript.quit
End If
Set objVerbs = objFolderItem.Verbs
'If only one argument list verbs for that item
If Ag.count = 1 then
For Each cmd in objFolderItem.Verbs
If len(cmd) <> 0 then CmdList = CmdList & vbcrlf & replace(cmd.name, "&", "")
Next
wscript.echo mid(CmdList, 2)
'If two arguments do verbs for that item
ElseIf Ag.count = 2 then
For Each cmd in objFolderItem.Verbs
If lcase(replace(cmd, "&", "")) = LCase(Ag(1)) then
wscript.echo Cmd.doit
Exit For
End If
Next
'Properties is special cased. Script has to stay running for Properties dialog to show.
If Lcase(Ag(1)) = "properties" then
WSHShell.AppActivate(ObjFolderItem.Name & " Properties")
msgbox "This message box has to stay open to keep the " & ObjFolderItem.Name & " Properties dialog open."
End If
End If
End If
You dont need the FSO for folder browse dialogue. Try shApp.BrowseForFolder(0, "Select Folder to print from", 0, 0). By this method you get directly the shell folder object. Also you may need to check each folder-item if is file or folder.
Sub printFgOO()
Dim shApp As Shell32.Shell
Dim shFIcol As Shell32.FolderItems
Dim shFIx As Shell32.FolderItem
Dim shFLDx As Shell32.Folder
Dim lngX As Long
Set shApp = New Shell32.Shell
Set shFLDx = shApp.BrowseForFolder(0, "Select Folder to print from", 0, 0)
Set shFIcol = shFLDx.Items()
For Each shFIx In shFIcol
If Not shFIx.IsFolder Then ' Print only if is file
shFIx.InvokeVerb ("&Print")
DoEvents
End If
Next
End Sub
OR try function ShellExecute as described here!
Okay, so I still don't have an answer as to WHY the InvokeVerb method was not working to print, but I do have a way to print files now using the ShellExecute function suggested by #Radek.
Figured I would share my working code here. Feel free to suggest improvements ;)
Option Explicit
Public Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteW" (ByVal hWnd As Long, _
ByVal lpOperation As LongPtr, _
ByVal lpFile As LongPtr, _
ByVal lpParameters As LongPtr, _
ByVal lpDirectory As LongPtr, _
ByVal nShowCmd As Long) As Long
Public Const SW_HIDE As Long = 0
'Hides the window and activates another window.
Public Const SW_MAXIMIZE As Long = 3
'Maximizes the specified window.
Public Const SW_MINIMIZE As Long = 6
'Minimizes the specified window and activates the next top-level window in the z-order.
Public Const SW_RESTORE As Long = 9
'Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when restoring a minimized window.
Public Const SW_SHOW As Long = 5
'Activates the window and displays it in its current size and position.
Public Const SW_SHOWDEFAULT As Long = 10
'Sets the show state based on the SW_ flag specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. An application should call ShowWindow with this flag to set the initial show state of its main window.
Public Const SW_SHOWMAXIMIZED As Long = 3
'Activates the window and displays it as a maximized window.
Public Const SW_SHOWMINIMIZED As Long = 2
'Activates the window and displays it as a minimized window.
Public Const SW_SHOWMINNOACTIVE As Long = 7
'Displays the window as a minimized window. The active window remains active.
Public Const SW_SHOWNA As Long = 8
'Displays the window in its current state. The active window remains active.
Public Const SW_SHOWNOACTIVATE As Long = 4
'Displays a window in its most recent size and position. The active window remains active.
Public Const SW_SHOWNORMAL As Long = 1
'Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
Public Enum shexActions
shexEDIT
shexEXPLORE
shexFIND
shexOPEN
shexPRINT
End Enum
Private Function getShellAction(ByRef enACTION As shexActions) As String
Select Case enACTION
Case shexActions.shexEDIT
getShellAction = "EDIT"
Case shexActions.shexEXPLORE
getShellAction = "EXPLORE"
Case shexActions.shexFIND
getShellAction = "FIND"
Case shexActions.shexOPEN
getShellAction = "OPEN"
Case shexActions.shexprint
getShellAction = "PRINT"
End Select
End Function
Public Function ShellEx(ByRef strFILE As String, _
Optional ByRef lngWINDOWHANDLE As Long = 0, _
Optional ByRef shexACTION As shexActions = (-1), _
Optional ByRef strPARAMETERS As String, _
Optional ByRef strDIRECTORY As String, _
Optional ByRef lngSHOWCOMMAND As Long = 0) As Long
Dim lngReturnCheck As Long
lngReturnCheck = (-1)
lngReturnCheck = ShellExecute(hWnd:=lngWINDOWHANDLE, lpOperation:=StrPtr(getShellAction(shexACTION)), lpFile:=StrPtr(strFILE), lpParameters:=StrPtr(strPARAMETERS), lpDirectory:=StrPtr(strDIRECTORY), nShowCmd:=lngSHOWCOMMAND)
While lngReturnCheck = (-1)
DoEvents
Wend
ShellEx = lngReturnCheck
End Function
Sub printBAR()
Dim shFIcol As Shell32.FolderItems
Dim shFIx As Shell32.FolderItem
Dim shFLDx As Shell32.Folder
Dim lngX As Long
Set shFLDx = GetFolder("Choose a folder...", True)
Set shFIcol = shFLDx.Items()
For Each shFIx In shFIcol
lngX = ShellEx(shFIx.Path, , shexPRINT)
Debug.Print lngX
Next
End Sub
If you are open to using powershell to solve this:
#Save this as Print-Files.ps1
[CmdletBinding()]
param(
[Property(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[string]$Path)
foreach($file in (Get-ChildItem $path ))
{
Start-Process –FilePath $file.FullName –Verb Print
}