Add line from excel VBA without the running file - vba
I just need the IF line that says that if he tries to open the file that runs the code(Trying to open himself) then skip it.
Here is the code I have so far.
Sub Auto_Open()
Dim SrcBook As Workbook
Dim fso As Object, f As Object, ff As Object, f1 As Object
Application.ScreenUpdating = False
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.Getfolder("C:\test\new")
Set ff = f.Files
For Each f1 In ff
Set SrcBook = Workbooks.Open(f1)
Range("A2:IV" & Range("A20").End(xlUp).Row).Copy
ThisWorkbook.Worksheets(1).Activate
Range("A20").End(xlUp).Offset(1, 0).PasteSpecial
Application.CutCopyMode = False
SrcBook.Close
Next
End Sub
If Not ThisWorkbook.FullName = f1.Path Then
Set SrcBook = Workbooks.Open(f1)
Range("A2:IV" & Range("A20").End(xlUp).Row).Copy
ThisWorkbook.Worksheets(1).Activate
Range("A20").End(xlUp).Offset(1, 0).PasteSpecial
Application.CutCopyMode = False
SrcBook.Close
End If
Taking your code as is, you could add the following If-statement to the For Each-loop:
For Each f1 In ff
If StrComp(f1.Name, ActiveWorkbook.Name, vbTextCompare) <> 0 And _
InStr(1, f1.Name, "~") = 0 Then
Set SrcBook = Workbooks.Open(f1)
Range("A2:IV" & Range("A20").End(xlUp).Row).Copy
ThisWorkbook.Worksheets(1).Activate
Range("A20").End(xlUp).Offset(1, 0).PasteSpecial
Application.CutCopyMode = False
SrcBook.Close
End If
Next
The first condition prevents opening the current file itself, the second condition also skips the temporary file that Excel creates on opening a file.
Reworked Code
Just as an aside, I would refactor and expand the code as follows:
Sub Auto_Open()
On Error GoTo Err_
Dim fso As Object
Dim Folder As Object
Dim Files As Object
Dim File As Object
Application.ScreenUpdating = False
Set fso = CreateObject("Scripting.FileSystemObject")
Set Folder = fso.Getfolder("C:\Temp\Excel")
Set Files = Folder.Files
For Each File In Files
If StrComp(File.Name, ActiveWorkbook.Name, vbTextCompare) <> 0 And _
InStr(1, File.Name, "~") = 0 Then
With Workbooks.Open(File.Path)
Range("A2:IV" & Range("A20").End(xlUp).Row).Copy
ThisWorkbook.Worksheets(1).Activate
Range("A20").End(xlUp).Offset(1, 0).PasteSpecial
Application.CutCopyMode = False
.Close
End With
End If
Next
Exit_:
Application.ScreenUpdating = True
Set Files = Nothing
Set Folder = Nothing
Set fso = Nothing
Exit Sub
Err_:
Resume Exit_
End Sub
A few remarks:
Error handling to ensure that even in the case of an error ScreenUpdating is switched back on again. Otherwise you could leave your application not refreshing to the user in case of an error.
Separate line for each variable - easier to grasp
More explicit variable names. First and foremost, code should be easy to read, not easy to type.
With-block for the local variable to make it's scope explicit. Saves the local variable SrcBook as well.
Here it might be argued that the name of that variable helped understanding the problem and should better be kept.
Explicit setting the object variables to Nothing. Might be paranoid, but as a SOP it can help to avoid all kind of weird issues in some cases.
Since it might be challenging to get the intent of the code in the With-block is, I would even go further and extract that block into a new method with a intent-revealing name to make things clearer. The name could be along the lines of CopyProductListFromFile.
Related
Excel VBA - Running a Macro against all files in a folder [duplicate]
I have a folder where I receive 1000+ excel files on daily bases they all are same format and structure. What I want to do is run a macro on all 100+ files on daily bases ? Is there way to automate this ? So I can keep running that same macro on 1000+ files daily.
Assuming that you put your files in "Files" directory relative to your master workbook your code might look like this: Sub ProcessFiles() Dim Filename, Pathname As String Dim wb As Workbook Pathname = ActiveWorkbook.Path & "\Files\" Filename = Dir(Pathname & "*.xls") Do While Filename <> "" Set wb = Workbooks.Open(Pathname & Filename) DoWork wb wb.Close SaveChanges:=True Filename = Dir() Loop End Sub Sub DoWork(wb As Workbook) With wb 'Do your work here .Worksheets(1).Range("A1").Value = "Hello World!" End With End Sub In this example DoWork() is your macro that you apply to all of your files. Make sure that you do all your processing in your macro is always in the context of the wb (currently opened workbook). Disclaimer: all possible error handling skipped for brevity.
A part of the question might be how do I run this on 1000 files?... Do I have to add this macro to all 1000 workbooks? One way to do this is to add your macro's centrally to the file PERSONAL.XLSB (sometimes the extension might be different). This file will be loaded in the background every time you start Excel and makes your macro's available at any time. Initially the PERSONAL.XLSB file will NOT be there. To automatically create this file, just start recording a "dummy" macro (with the record button on the left-bottom of a spreadsheet) and select "Personal Macro Workbook" to store it in. After recording your macro, you can open the VBA editor with Alt+F11 and you will see the PERSONAL.XLSB file with the "dummy" recorded macro. I use this file to store loads of general macro's which are always available, independent of which .xlsx file I have open. I have added these macro's to my own menu ribbon. One disadvantage of this common macro file is that if you launch more than one instance of Excel, you will get an error message that the PERSONAL.XLSB file is already in use by Excel instance Nr. 1. This is no problem as long as you do not add new macro's at this moment.
Thank you very much for this Sub ProcessFiles() Dim Filename, Pathname As String Dim wb As Workbook Pathname = ActiveWorkbook.Path & "C:\Users\jkatanan\Desktop\20170206Glidepath\V37\" Filename = Dir(Pathname & "*.xls") Do While Filename <> "" Set wb = Workbooks.Open(Pathname & Filename) BSAQmacro wb wb.Close SaveChanges:=True Filename = Dir() Loop End Sub Sub DoWork(wb As Workbook) With wb 'Do your work here .Worksheets(1).Range("A1").Value = "Hello World!" End With End Sub
Sub ProcessFiles() Dim Filename, Pathname As String Dim wb As Workbook Pathname = ActiveWorkbook.Path & "\C:\Users\20098323\Desktop\EXCL\" Filename = Dir(Pathname & "*.xlsx") Do While Filename <> "" Set wb = Workbooks.Open(Pathname & Filename) DoWork wb wb.Close SaveChanges:=True Filename = Dir() Loop End Sub Sub DoWork(wb As Workbook) With wb 'Do your work here .Worksheets(1).Range("A1").Value = "Hello World!" End With End Sub While running this code its showing bad file name or number. i have stored my all file in ("\C:\Users\20098323\Desktop\EXCL\") EXCL folder
Instead of passing the values to DoWork one can also run the jobs in Processfiles(). Sub ProcessFiles() Dim Filename, Pathname As String Dim wb1 As Workbook Dim wb2 As Workbook Dim Sheet As Worksheet Dim PasteStart As Range Dim Counter As Integer Set wb1 = ActiveWorkbook Set PasteStart = [RRimport!A1] Pathname = ActiveWorkbook.Path & "\For Macro to run\" Filename = Dir(Pathname & "*.xls") Do While Filename <> "" Set wb2 = Workbooks.Open(Pathname & Filename) For Each Sheet In wb2.Sheets With Sheet.UsedRange .Copy PasteStart Set PasteStart = PasteStart.Offset(.Rows.Count) End With Next Sheet wb2.Close Filename = Dir() Loop End Sub
This isn't an exact answer to the question, since I was just trying to run a single script on any file that I opened and couldn't get that to work, but I thought this might help others like me. It worked once I moved the code into a Module in the Visual Basic for Applications dialog box (go to "Insert" then "Module"). Once I added my VBA code to a module, I was able to open any other file in Excel (even a CSV file) and go to Macros, and run the Macro from the other file (that contains the Module with the code) on the file that I had open.
Thanks Peterm!! Actually, I did my macro using exactly the same code you posted (process_fiels and dowork). It worked brilliant!! (before my question) Each of my 1000 workbooks has 84 worksheets. My own macro (which finally works!) splits each workbook into 85 different files (the original + a short version of each worksheet saved as an individual file). That leaves me with 1000 files + 1000x85 in the same folder, and that would be really hard to sort out. What I really need is for Process_Files to take the first file, create a folder with the name of the first file, move the first file to the folder with ist name, then run my macro (in the folder named after the first file in the newly created folder...), go back and take the second file, create a folder with the name of the second file, move the second file to the folder with ist name, then run my macro (in the folder named after the second file in the newly created folder...), etc... At the end, I should have moved all files into folders with the same name as the files, and the contents of the original \Files\ folder would be 1000 folders with the name of the original files, containgin the original files + 84 files which my own macro already does. Maybe it is easier with the code: Sub ProcessFiles() Dim Filename, Pathname As String Dim wb As Workbook Pathname = ActiveWorkbook.Path & "\Files\" Filename = Dir(Pathname & "*.xls") Do While Filename <> "" (Here, it should read the file name, create a folder with the file name, move the file into this newly created folder) Set wb = Workbooks.Open(Pathname & Filename) <- open file, just as is. DoWork wb <- do my macro,just as is wb.Close SaveChanges:=False <- not save, to keep the original file (go back to the original \Files\ folder) Filename = Dir() <- Next file, just as is Loop End Sub Sub DoWork(wb As Workbook) With wb MyMacro End With End Sub Many thanks, this site is great! __________________edit, the macro now works _________________________ As you can see, I am no VBA expert, but the macro finally works. The code is not neat at all, I am no SW programmer. Here it is, it might help some one some day. Sub ProcessFiles_All() Dim Filename, Pathname, NewPath, FileSource, FileDestination As String Dim wb As Workbook Pathname = ActiveWorkbook.Path & "\Files\" Filename = Dir(Pathname & "*.csv") Do While Filename <> "" NewPath = Pathname & Left(Filename, 34) & "\" On Error Resume Next MkDir (NewPath) On Error GoTo 0 Set wb = Workbooks.Open(Pathname & Filename) DoWorkPlease wb ' <------------ It is important to say please!! On Error Resume Next wb.Close SaveChanges:=False if Err.Number <> 0 then ‘Error handler needed here End if Filename = Dir() Loop End Sub Sub DoWorkPlease(wb As Workbook) With wb ‘ Since my application has over 1800 cells for each column and it is time consuming ‘ I use a “testing mode” were I only play with 18 values. Dim TestingMode As Integer Dim ThisRange(1 To 4) As Variant TestingMode = 0 If TestingMode = 1 Then ThisRange(1) = "B2:CG18" ThisRange(2) = "CT2:CT18" ThisRange(3) = "CH2:CN18" ThisRange(4) = "CN2:CS18" Rows("19:18201").Select Selection.Delete Shift:=xlUp End If If TestingMode = 0 Then ThisRange(1) = "B2:CG18201" ThisRange(2) = "CT2:CT18201" ThisRange(3) = "CH2:CN18201" ThisRange(4) = "CN2:CS18201" End If ‘ speed up the macro, turn off updating and alerts Application.ScreenUpdating = False Application.DisplayAlerts = False ‘ Here is my code that manipulates the cell values from digits (values read by sensors need to be “translated” into real world values. Code not here actually. ‘Then I copy the whole thing into just numbers, there are no longer formulas, easier to work this way. '_____________________________________ 'Get just values - no more formulas Sheets.Add After:=Sheets(Sheets.Count) Sheets("Sheet1").Select Columns("A:CT").Select Selection.Copy Sheets("Sheet2").Select Columns("A:A").Select Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _ :=False, Transpose:=False Application.CutCopyMode = False Selection.NumberFormat = "0" With Selection .HorizontalAlignment = xlCenter .VerticalAlignment = xlBottom .WrapText = False .Orientation = 0 .AddIndent = False .IndentLevel = 0 .ShrinkToFit = False .ReadingOrder = xlContext .MergeCells = False End With ‘ Then I save this new workbook into a folder with its own name (and under the folder \FILES\ '_____________________________________ 'Save the work under its own folder Dim CleanName, CleanPath, CleanNewName As Variant CleanPath = ActiveWorkbook.Path CleanName = ActiveWorkbook.Name CleanName = Left(CleanName, 34) ‘I take out the extension CleanPath = CleanPath + "\" + CleanName CleanNewName = CleanPath + "\" + CleanName CleanNewName = CleanNewName + "_clean.csv" ‘ and I add “clean” to have a different name now. On Error Resume Next ActiveWorkbook.SaveAs Filename:=CleanNewName, FileFormat:=xlCSV, CreateBackup:=False ‘If there is an error I create an empty folder with the name of the file to know which file needs rework. If Err.Number <> 0 Then MkDir (CleanPath + "_error_" + CleanName) End If 'Resume Next ActiveSheet.Move _ After:=ActiveWorkbook.Sheets(1) ‘ Then I split the workbook into individual files with the data I need for individual sensors. ‘ Here are the individual ranges I need for each file. Since I have over 1000 files, it is worth the effort. '_______________ the Split!!______________________________ Dim Col(1 To 98) As Variant Col(1) = "A:A,B:B,CH:CH,CN:CN,CT:CT" Col(2) = "A:A,C:C,CH:CH,CN:CN,CT:CT" Col(3) = "A:A,D:D,CH:CH,CN:CN,CT:CT" Col(4) = "A:A,E:E,CH:CH,CN:CN,CT:CT" Col(5) = "A:A,F:F,CH:CH,CN:CN,CT:CT" Col(6) = "A:A,G:G,CH:CH,CN:CN,CT:CT" Col(7) = "A:A,H:H,CH:CH,CN:CN,CT:CT" Col(8) = "A:A,I:I,CH:CH,CN:CN,CT:CT" Col(9) = "A:A,J:J,CH:CH,CN:CN,CT:CT" Col(10) = "A:A,K:K,CH:CH,CN:CN,CT:CT" Col(11) = "A:A,L:L,CH:CH,CN:CN,CT:CT" Col(12) = "A:A,M:M,CH:CH,CN:CN,CT:CT" Col(13) = "A:A,N:N,CH:CH,CN:CN,CT:CT" Col(14) = "A:A,O:O,CH:CH,CN:CN,CT:CT" Col(15) = "A:A,P:P,CI:CI,CO:CO,CT:CT" Col(16) = "A:A,Q:Q,CI:CI,CO:CO,CT:CT" Col(17) = "A:A,R:R,CI:CI,CO:CO,CT:CT" Col(18) = "A:A,S:S,CI:CI,CO:CO,CT:CT" Col(19) = "A:A,T:T,CI:CI,CO:CO,CT:CT" Col(20) = "A:A,U:U,CI:CI,CO:CO,CT:CT" Col(21) = "A:A,V:V,CI:CI,CO:CO,CT:CT" Col(22) = "A:A,W:W,CI:CI,CO:CO,CT:CT" Col(23) = "A:A,X:X,CI:CI,CO:CO,CT:CT" Col(24) = "A:A,Y:Y,CI:CI,CO:CO,CT:CT" Col(25) = "A:A,Z:Z,CI:CI,CO:CO,CT:CT" Col(26) = "A:A,AA:AA,CI:CI,CO:CO,CT:CT" Col(27) = "A:A,AB:AB,CI:CI,CO:CO,CT:CT" Col(28) = "A:A,AC:AC,CI:CI,CO:CO,CT:CT" Col(29) = "A:A,AD:AD,CJ:CJ,CP:CP,CT:CT" Col(30) = "A:A,AE:AE,CJ:CJ,CP:CP,CT:CT" Col(31) = "A:A,AF:AF,CJ:CJ,CP:CP,CT:CT" Col(32) = "A:A,AG:AG,CJ:CJ,CP:CP,CT:CT" Col(33) = "A:A,AH:AH,CJ:CJ,CP:CP,CT:CT" Col(34) = "A:A,AI:AI,CJ:CJ,CP:CP,CT:CT" Col(35) = "A:A,AJ:AJ,CJ:CJ,CP:CP,CT:CT" Col(36) = "A:A,AK:AK,CJ:CJ,CP:CP,CT:CT" Col(37) = "A:A,AL:AL,CJ:CJ,CP:CP,CT:CT" Col(38) = "A:A,AM:AM,CJ:CJ,CP:CP,CT:CT" Col(39) = "A:A,AN:AN,CJ:CJ,CP:CP,CT:CT" Col(40) = "A:A,AO:AO,CJ:CJ,CP:CP,CT:CT" Col(41) = "A:A,AP:AP,CJ:CJ,CP:CP,CT:CT" Col(42) = "A:A,AQ:AQ,CJ:CJ,CP:CP,CT:CT" Col(43) = "A:A,AR:AR,CK:CK,CQ:CQ,CT:CT" Col(44) = "A:A,AS:AS,CK:CK,CQ:CQ,CT:CT" Col(45) = "A:A,AT:AT,CK:CK,CQ:CQ,CT:CT" Col(46) = "A:A,AU:AU,CK:CK,CQ:CQ,CT:CT" Col(47) = "A:A,AV:AV,CK:CK,CQ:CQ,CT:CT" Col(48) = "A:A,AW:AW,CK:CK,CQ:CQ,CT:CT" Col(49) = "A:A,AX:AX,CK:CK,CQ:CQ,CT:CT" Col(50) = "A:A,AY:AY,CK:CK,CQ:CQ,CT:CT" Col(51) = "A:A,AZ:AZ,CK:CK,CQ:CQ,CT:CT" Col(52) = "A:A,BA:BA,CK:CK,CQ:CQ,CT:CT" Col(53) = "A:A,BB:BB,CK:CK,CQ:CQ,CT:CT" Col(54) = "A:A,BC:BC,CK:CK,CQ:CQ,CT:CT" Col(55) = "A:A,BD:BD,CK:CK,CQ:CQ,CT:CT" Col(56) = "A:A,BE:BE,CK:CK,CQ:CQ,CT:CT" Col(57) = "A:A,BF:BF,CL:CL,CR:CR,CT:CT" Col(58) = "A:A,BG:BG,CL:CL,CR:CR,CT:CT" Col(59) = "A:A,BH:BH,CL:CL,CR:CR,CT:CT" Col(60) = "A:A,BI:BI,CL:CL,CR:CR,CT:CT" Col(61) = "A:A,BJ:BJ,CL:CL,CR:CR,CT:CT" Col(62) = "A:A,BK:BK,CL:CL,CR:CR,CT:CT" Col(63) = "A:A,BL:BL,CL:CL,CR:CR,CT:CT" Col(64) = "A:A,BM:BM,CL:CL,CR:CR,CT:CT" Col(65) = "A:A,BN:BN,CL:CL,CR:CR,CT:CT" Col(66) = "A:A,BO:BO,CL:CL,CR:CR,CT:CT" Col(67) = "A:A,BP:BP,CL:CL,CR:CR,CT:CT" Col(68) = "A:A,BQ:BQ,CL:CL,CR:CR,CT:CT" Col(69) = "A:A,BR:BR,CL:CL,CR:CR,CT:CT" Col(70) = "A:A,BS:BS,CL:CL,CR:CR,CT:CT" Col(71) = "A:A,BT:BT,CM:CM,CS:CS,CT:CT" Col(72) = "A:A,BU:BU,CM:CM,CS:CS,CT:CT" Col(73) = "A:A,BV:BV,CM:CM,CS:CS,CT:CT" Col(74) = "A:A,BW:BW,CM:CM,CS:CS,CT:CT" Col(75) = "A:A,BX:BX,CM:CM,CS:CS,CT:CT" Col(76) = "A:A,BY:BY,CM:CM,CS:CS,CT:CT" Col(77) = "A:A,BZ:BZ,CM:CM,CS:CS,CT:CT" Col(78) = "A:A,CA:CA,CM:CM,CS:CS,CT:CT" Col(79) = "A:A,CB:CB,CM:CM,CS:CS,CT:CT" Col(80) = "A:A,CC:CC,CM:CM,CS:CS,CT:CT" Col(81) = "A:A,CD:CD,CM:CM,CS:CS,CT:CT" Col(82) = "A:A,CE:CE,CM:CM,CS:CS,CT:CT" Col(83) = "A:A,CF:CF,CM:CM,CS:CS,CT:CT" Col(84) = "A:A,CG:CG,CM:CM,CS:CS,CT:CT" ‘ I want to split 84 new files, so for testing I use only 1, and for the real thing I go with 84 Dim CounterMode As Integer If TestingMode = 1 Then CounterMode = 1 Else CounterMode = 84 For i = 1 To CounterMode ‘ this code takes the columns need, and paste it into a new workbook. Sheets("Sheet1").Select Cells.Select Selection.ClearContents Range("A1").Activate Sheets(2).Select Range(Col(i)).Select Selection.Copy Sheets("Sheet1").Select ActiveSheet.Paste Application.CutCopyMode = False With Selection .HorizontalAlignment = xlCenter .VerticalAlignment = xlBottom .WrapText = False .Orientation = 0 .AddIndent = False .IndentLevel = 0 .ShrinkToFit = False .ReadingOrder = xlContext .MergeCells = False End With Columns("A:E").EntireColumn.AutoFit ‘ Save the individual file '_____________save the work________________ Dim ThePath, TheName, TheSwitch As String ThePath = ActiveWorkbook.Path + “\” TheName = Left(ActiveWorkbook.Name, 34) ‘ take out the extension from the name ThePath = ThePath + TheName TheSwitch = Cells(3, 2) ‘ In Cell (3,2) I have the name of the individual name, so I added to the file name. TheName = ThePath + "_" + TheSwitch + ".xls" Range("A1").Select Sheets("Sheet1").Select Sheets("Sheet1").Copy Dim SheetName As Variant ‘ I name Sheets(1) as Sheet1, since the original sheet has the name and date of the test. ‘ I do this to have the same name on all file in order to do a plot, then I rename the sheet with the ‘ original name SheetName = ActiveSheet.Name ActiveWorkbook.Sheets(1).Name = "Sheet1" ‘ here is the plot Columns("A:E").EntireColumn.AutoFit Columns("B:E").Select ActiveSheet.Shapes.AddChart.Select ActiveChart.SetSourceData Source:=Range("'Sheet1'!$B:$E") ActiveChart.ChartType = xlXYScatterLinesNoMarkers ActiveWorkbook.Sheets(1).Name = SheetName ‘save On Error Resume Next ActiveWorkbook.SaveAs Filename:=TheName, FileFormat:=56, CreateBackup:=False If Err.Number <> 0 Then MkDir (ThePath + "_error_" + TheName) End If ActiveWorkbook.Close Next i '____________________That was the Split__________________________________ ' Turn on screenupdating: Application.ScreenUpdating = True Application.DisplayAlerts = True Range("A1").Select End With End Sub
PasteSpecial Method Odd Error
I have gone through the similar questions and have not found anything with this specific error. I am trying to make a macro that goes through a large number of CSV files, pulls the necessary information I need, copies and pastes that data to a new Workbook, and then closes the CSV file and goes to the next one. When I test my code and have it run Step by Step (using F8) it functions fine and there are no error. However, whenever I try and just have the code run (like pressing F5) I get the error "PasteSpecial Method of Class Range" failed. When I press debug this line of the code is highlighted: copyRange.Offset(0, 1).PasteSpecial Paste:=xlPasteValues I added a small time delay of 0.5s before this line and it actually was able to go further through the files before failing. Is it something with the Range.Offset method? Should I explicitly define a different copy range? Code I have follows below: Public Sub OpenTXT_CopyNewWBK(inPath As String) Application.ScreenUpdating = False Dim fso, oFolder, oSubfolder, oFile, queue As Collection Dim app As New Excel.Application app.Visible = True Dim dataRange As Range, dateRange As Range, copyRange As Range Dim lastCell, lastRow As String Dim newBook, wbk As Excel.Workbook Dim csvStart As Long Set newBook = Workbooks.Add With newBook .SaveAs Filename:="BETA RAY " & Format(Now, "ddmmyyhhmmss") End With Set fso = CreateObject("Scripting.FileSystemObject") Set queue = New Collection queue.Add fso.GetFolder(inPath) 'obviously replace Set objExcel = CreateObject("Excel.Application") objExcel.Visible = True Do While queue.Count > 0 Set oFolder = queue(1) queue.Remove 1 'dequeue For Each oSubfolder In oFolder.SubFolders queue.Add oSubfolder 'enqueue Next oSubfolder For Each oFile In oFolder.Files Set wbk = app.Workbooks.Add(oFile.Path) lastCell = wbk.Sheets(1).Range("A1").End(xlDown).Address If Len(lastCell) = 6 Then lastRow = Mid(lastCell, 4, 3) ElseIf Len(lastCell) = 5 Then lastRow = Mid(lastCell, 4, 2) ElseIf Len(lastCell) = 4 Then lastRow = Mid(lastCell, 4, 1) End If Set dateRange = wbk.Sheets(1).Range("A2", lastCell) dateRange.Select Set dataRange = wbk.Sheets(1).Range("AA2", "AM" & lastRow) dataRange.Select wbk.Application.CutCopyMode = True Set copyRange = Workbooks(newBook.name).Sheets(1).Range("A1048576").End(xlUp) If Not copyRange = "" Then Set copyRange = copyRange.Offset(1, 0) End If dateRange.Copy copyRange.PasteSpecial Paste:=xlPasteValues wbk.Application.CutCopyMode = False wbk.Application.CutCopyMode = True Application.Wait (Now + 500 * 0.00000001) dataRange.Copy copyRange.Offset(0, 1).PasteSpecial Paste:=xlPasteValues wbk.Application.CutCopyMode = False wbk.Close SaveChanges:=False Next oFile Loop app.Quit Set app = Nothing Range("B:B").Delete Range("G:G").Delete Range("L:L").Delete Application.ScreenUpdating = True End Sub I am sure there are much better ways to do a lot of the things I have going on there. I really just use VBA to make my life easier at work so a lot of the code I use is copy, pasted, and modified to fit my needs. I couldn't figure out how to make this method work wbk2.sht2.Range("A1:A5") = wbk1.sht1.Range("B1:B5") everything I have read says this should be a much better method. Also, the portions of code that read dataRange.Select and dateRange.Select are just there for debugging purposes.
try this.... wbk2.sht2.Range("A1:A5").value = wbk1.sht1.Range("B1:B5").value
Unable to Sort XLS data using Range.Sort
I have a xl file with about 2000 rows and columns from A to H. I was trying to sort the file based on the column D such that all other columns are also sorted accordingly (expand selection area). I am very new to Macros and have been doing this small task to save some time on my reporting. Here's what I tried: Prompt the user to select a file Set the columns from A to H Sort Range as D2 Save the file As I said, I am new, I have used much of the code from sample examples in the MSDN library. Apart from Sort(), every thing else is working for me. here's the code Sub Select_File_Windows() Dim SaveDriveDir As String Dim MyPath As String Dim Fname As Variant Dim N As Long Dim FnameInLoop As String Dim mybook As Workbook Dim SHEETNAME As String 'Default Sheet Name SHEETNAME = "Sheet1" ' Save the current directory. SaveDriveDir = CurDir ' Set the path to the folder that you want to open. MyPath = Application.DefaultFilePath ' Open GetOpenFilename with the file filters. Fname = Application.GetOpenFilename( _ FileFilter:="XLS Files (*.xls),*.xls,XLSX Files (*.xlsx),*.xlsx", _ Title:="Select a file", _ MultiSelect:=True) ' Perform some action with the files you selected. If IsArray(Fname) Then With Application .ScreenUpdating = False .EnableEvents = True End With For N = LBound(Fname) To UBound(Fname) ' Get only the file name and test to see if it is open. FnameInLoop = Right(Fname(N), Len(Fname(N)) - InStrRev(Fname(N), Application.PathSeparator, , 1)) If bIsBookOpen(FnameInLoop) = False Then Set mybook = Nothing On Error Resume Next Set mybook = Workbooks.Open(Fname(N)) On Error GoTo 0 DoEvents If Not mybook Is Nothing Then Debug.Print "You opened this file : " & Fname(N) & vbNewLine With mybook.Sheets(SHEETNAME) 'Columns("A:H").Sort Key1:=Range("D2:D2000"), Order1:=xlAscending, Header:=xlYes 'Range("A1:H2000").Sort Key1:=Range("D1"), Order1:=xlAscending Columns("A:H").Sort Key1:=Range("D1"), Order1:=xlAscending, Header:=xlYes End With Debug.Print "Sorter Called" mybook.Close SaveChanges:=True End If Else Debug.Print "We skipped this file : " & Fname(N) & " because it is already open. Please close the data file and try again" End If Next N With Application .ScreenUpdating = True .EnableEvents = True End With End If End Sub Function bIsBookOpen(ByRef szBookName As String) As Boolean On Error Resume Next bIsBookOpen = Not (Application.Workbooks(szBookName) Is Nothing) End Function Nothing is working for me. The file stays as is and No update is made to it. I could not understand, what is the newbie mistake I have been making here ? Please help. References: https://msdn.microsoft.com/en-us/library/office/ff840646(v=office.15).aspx http://analysistabs.com/vba/sort-data-ascending-order-excel-example-macro-code/ Run time error 1004 when trying to sort data on three different values
It may be as simple as adding a couple of dots (see pentultimate line below) With mybook.Sheets(SHEETNAME) 'Columns("A:H").Sort Key1:=Range("D2:D2000"), Order1:=xlAscending, Header:=xlYes 'Range("A1:H2000").Sort Key1:=Range("D1"), Order1:=xlAscending .Columns("A:H").Sort Key1:=.Range("D1"), Order1:=xlAscending, Header:=xlYes End With
SJR is correct in saying that your references should be fully qualified inside of the With Statement. You should simplify your subroutines by extracting large blocks of code into separate subroutines. The fewer tasks that a subroutines handles, the easier it is to read and to debug. Refactored Code Sub Select_File_Windows() Const SHEETNAME As String = "Sheet1" Dim arExcelFiles Dim x As Long arExcelFiles = getExcelFileArray If UBound(arExcelFiles) = -1 Then Debug.Print "No Files Selected" Else ToggleEvents False For x = LBound(arExcelFiles) To UBound(arExcelFiles) If IsWorkbookOpen(arExcelFiles(x)) Then Debug.Print "File Skipped: "; arExcelFiles(x) Else Debug.Print "File Sorted: "; arExcelFiles(x) With Workbooks.Open(arExcelFiles(x)) With .Sheets(SHEETNAME) .Columns("A:H").Sort Key1:=.Range("D1"), Order1:=xlAscending, Header:=xlYes End With .Close SaveChanges:=True End With End If Next ToggleEvents True End If End Sub Function IsWorkbookOpen(ByRef szBookName As String) As Boolean On Error Resume Next IsWorkbookOpen = Not (Application.Workbooks(szBookName) Is Nothing) End Function Function getExcelFileArray() Dim result result = Application.GetOpenFilename( _ FileFilter:="Excel Workbooks, *.xls; *.xlsx", _ Title:="Select a file", _ MultiSelect:=True) If IsArray(result) Then getExcelFileArray = result Else getExcelFileArray = Array() End If End Function Sub ToggleEvents(EnableEvents As Boolean) With Application .ScreenUpdating = EnableEvents .Calculation = IIf(EnableEvents, xlCalculationAutomatic, xlCalculationManual) .EnableEvents = EnableEvents End With End Sub
Changing a VBA script using a VBScript or CMD
I have looked everywhere and I didn't find any solution for my problem. What I need is to change a part of my VBA using a VBscript (or even a CMD). I have something like this: Sub Test If ActiveSheet.AutoFilterMode = True Then ActiveSheet.AutoFilterMode = False NameColumn = Application.WorksheetFunction.Match("Names", Range(Cells(line, column), Cells(line, column + 30)), 0) Cells(line, colum).Select Selection.AutoFilter Field:=NameColumn, Criteria1:="=*ABC*", _ Operator:=xlAnd Selection.End(xlDown).Select If ActiveCell.Row < 1000 Then Call Copy("ABC") End If SendEmail("ABC is done", emailaddress) End Sub What I wanted is a script to change ABC to CDE, FGH and IJK, for instance. I have a script in VBS which change part of my code if I want: Const ToRead= 1 Const ToWrite= 2 File= Wscript.Arguments(0) OldText= Wscript.Arguments(1) NewText = Wscript.Arguments(2) Set objFSO = CreateObject("Scripting.FileSystemObject") Set objFile = objFSO.OpenTextFile(File, ToRead) strText = objFile.ReadAll objFile.Close NewText = Replace(strText, OldText, NewText) Set objFile = objFSO.OpenTextFile(File, ToWrite) objFile.Write NewText objFile.Close And I also have a code to run a VBA using a VBS: Sub ExcelMacroExample() Dim xlApp Dim xlBook Set xlApp = CreateObject("Excel.Application") Set xlBook = xlApp.Workbooks.Open("C:\Documents\Example.xlsm") xlApp.Run "RunMacro" xlApp.Quit Set xlBook = Nothing Set xlApp = Nothing End Sub However, I really cant see a connection between those scripts and I didnt find anything on the internet about this problem. Does anyone know how can I change a part of the VBA code using the VBS? Using VBS would be the best way to do that, because of other parts of the process I am running. But I would accept different answers.
What about using parametr for your Test sub and pass it using xlApp.Run: xlApp.Run "Example.xlsm!Test", "ABC" Test sub with parametr: Sub Test(str As String) If ActiveSheet.AutoFilterMode = True Then ActiveSheet.AutoFilterMode = False NameColumn = Application.WorksheetFunction.Match("Names", Range(Cells(Line, Column), Cells(Line, Column + 30)), 0) Cells(Line, colum).Select Selection.AutoFilter Field:=NameColumn, Criteria1:="=*" & str & "*", _ Operator:=xlAnd Selection.End(xlDown).Select If ActiveCell.Row < 1000 Then Call Copy(str) End If Call SendEmail(str & " is done", emailaddress) End Sub
Application defined or Object defined error in excel vba
I am new to excel. I need to create a new excel from the macro written and need to add some data and save it as a csv file. I am getting Application defined or Object defined error. Her is the code Sub splitIntoCsv() Dim wbIn Dim wbIn1 As Workbook Dim header As Variant Set wbIn = CreateObject("Excel.Application") wbIn.Workbooks.Add 'wbIn.Worksheets(1).Name = "TestData" 'Set wbIn1 = Workbooks.Open(Sheet1.Range("b25").Value, True, False) header = Split(ThisWorkbook.Sheets(1).Range("B2").Value, ",") For k = 1 To 10 DoEvents Next k For i = LBound(header) To UBound(header) 'MsgBox header(i) **wbIn.Worksheets(1).Range("a" & i).Value = header(i)** Next i wbIn.Worksheets(1).SaveAs Filename:="D:\file.csv" & Filename, FileFormat:=xlCSV, CreateBackup:=False End Sub I got the error at the Starred lines.Help needed, Thanks in advance, Raghu.
The following code now work, Please have a look Sub splitIntoCsv() Dim wbIn As Excel.Application Dim wbIn1 As Workbook Dim header As Variant Set wbIn = CreateObject("Excel.Application") Set wbIn1 = wbIn.Workbooks.Add header = Split(ThisWorkbook.Sheets(1).Range("B2").Value, ",") For k = 1 To 10 DoEvents Next k For i = LBound(header) To UBound(header) '**wbIn1.Worksheets(1).Range("a" & i).Value = header(i)** Next i wbIn1.SaveAs Filename:="D:\file.csv" & Filename, FileFormat:=xlCSV, CreateBackup:=False wbIn1.Close Set wbIn1 = Nothing wbIn.Application.Quit Set wbIn = Nothing End Sub The first problem in the code was that you were trying to save using the worksheets. Worksheets do not have a save method, Workbooks do. While fixing the code, I had a large number of excel objects in memory. Please have a look at how to close and exit a excel application.
For the starred line you asked about, note that the Split function returns a zero-based array, so in your first time through the loop you are trying to refer to cell A0. So, change the line to: wbIn.Worksheets(1).Range("a" & i+1).Value = header(i)