List Hyperlinks in Excel - vba

I ahve an Excel work book containing a large number of sheets. Each sheet has between 1 and 12 Hyperlinks to different documents on a website. These dicuments are updated from time to time. I would like a macro that lists all the Hyperlinks in a new sheet but also lists the sheet name next to each link. I have the following that lists the Hyperlinks and the cell ref
Sub CopyHyperLinks()
Dim rCell As Range
Dim ws As Worksheet
Dim Lhyper As Long
On Error Resume Next
Application.DisplayAlerts = False
Sheets("Hypers").Delete
On Error Goto 0
Application.DisplayAlerts = True
Sheets.Add().Name = "Hypers"
For Each ws In Worksheets
If ws.Name <> "Hypers" Then
For Lhyper = 1 To ws.UsedRange.Hyperlinks.Count
ws.Hyperlinks(Lhyper).Range.Copy
With Sheets("Hypers").Cells(Rows.Count, 1).End(x1Up)
.Offset(1, 0).PasteSpecial
.Offset(1, 1) = ws.Hyperlinks(Lhyper).Range.Address
End
Application.CutCopyMode = False
Next Lhyper
End If
Next ws
End Sub
How can i modify this to show the sheet name instead of the cell ref.
is it also possible to then check that these Hyperlinks are valid destinations?

You can get the name of the worksheet of the hyperlink with this line:
ws.Hyperlinks(Lhyper)..Range.Worksheet.Name
Here's is your reworked code (it contained some other syntactical errors that I corrected):
Sub CopyHyperLinks()
Dim rCell As Range
Dim ws As Worksheet
Dim Lhyper As Long
Dim rngLink As Range
Application.DisplayAlerts = False
On Error Resume Next
Sheets("Hypers").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Sheets.Add().Name = "Hypers"
For Each ws In Worksheets
If ws.Name <> "Hypers" Then
For Lhyper = 1 To ws.UsedRange.Hyperlinks.Count
Set rngLink = ws.Hyperlinks(Lhyper).Range
rngLink.Copy
With Sheets("Hypers").Cells(Rows.Count, 1).End(xlUp)
.Offset(1, 0).PasteSpecial
.Offset(1, 1) = rngLink.Address
.Offset(1, 2) = rngLink.Worksheet.Name
.Offset(1, 3) = CheckHyperlink(ws.Hyperlinks(Lhyper).Address)
End With
Application.CutCopyMode = False
Next Lhyper
End If
Next ws
End Sub
If you want to verify the links, include the code from this answer. Include this line in your code:
.Offset(1, 3) = CheckHyperlink(ws.Hyperlinks(Lhyper).Address)
and also this routine:
Public Function CheckHyperlink(ByVal strUrl As String) As Boolean
Dim oHttp As New MSXML2.XMLHTTP30
On Error GoTo ErrorHandler
oHttp.Open "HEAD", strUrl, False
oHttp.send
If Not oHttp.Status = 200 Then CheckHyperlink = False Else CheckHyperlink = True
Exit Function
ErrorHandler:
CheckHyperlink = False
End Function
You need to include a reference to the "Microsoft XML" library in your VBA project.

Related

How do I apply a macro to multiple excel files when the macro contains many subs?

I have used a macro to track changes in a workbook, but I would now like to run this macro in over a 100 excel files within a particular folder using a Do While Loop.
I am very new to VBA and will appreciate all the help I can get.
I have come across some code that should enable me to loop through excel files in a folder and run the macro in each one.
However it requires me to get rid of the 'sub' and 'end sub' from the macro when I copy and paste it into the do while loop, but I have 3 of them within the macro; some variables will be undefined if I delete all 3.
Therefore I tried 'Call Tracker' within the loop ('Tracker' being the macro name) and hoped it would run in each excel file.
Sub LoopThroughFiles()
Dim xFd As FileDialog
Dim xFdItem As Variant
Dim xFileName As String
Set xFd = Application.FileDialog(msoFileDialogFolderPicker)
If xFd.Show = -1 Then
xFdItem = xFd.SelectedItems(1) & Application.PathSeparator
xFileName = Dir(xFdItem & "*,xls*")
Do While xFileName <> ""
With Workbooks.Open(xFdItem & xFileName)
'Your code here
Call Tracker
End With
xFileName = Dir
Loop
End If
End Sub
Below is the code inside 'Tracker'
Option Explicit
Dim sOldAddress As String
Dim vOldValue As Variant
Public Sub Workbook_TrackChange(Cancel As Boolean)
Dim Sh As Worksheet
For Each Sh In ActiveWorkbook.Worksheets
Sh.PageSetup.LeftFooter = "&06" & ActiveWorkbook.FullName & vbLf & "&A"
Next Sh
End Sub
Public Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim wSheet As Worksheet
Dim wActSheet As Worksheet
Dim iCol As Integer
Set wActSheet = ActiveSheet
'Precursor Exits
'Other conditions that you do not want to track could be added here
If vOldValue = "" Then Exit Sub 'If you comment out this line *every* entry will be recorded
'Continue
On Error Resume Next ' This Error-Resume-Next is only to allow the creation of the tracker sheet.
Set wSheet = Sheets("Tracker")
'**** Add the tracker Sheet if it does not exist ****
If wSheet Is Nothing Then
Set wActSheet = ActiveSheet
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = "Tracker"
End If
On Error GoTo 0
'**** End of specific error resume next
On Error GoTo ErrorHandler
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
With Sheets("Tracker")
'******** This bit of code moves the tracker over a column when the first columns are full**'
If .Cells(1, 1) = "" Then '
iCol = 1 '
Else '
iCol = .Cells(1, 256).End(xlToLeft).Column - 7 '
If Not .Cells(65536, iCol) = "" Then '
iCol = .Cells(1, 256).End(xlToLeft).Column + 1 '
End If '
End If '
'********* END *****************************************************************************'
.Unprotect Password:="Secret"
'******** Sets the Column Headers **********************************************************
If LenB(.Cells(1, iCol).Value) = 0 Then
.Range(.Cells(1, iCol), .Cells(1, iCol + 7)) = Array("Cell Changed", "SAP ID", "Field Name", "Old Field Value", _
"New Field Value", "Time of Change", "Date Stamp", "User")
.Cells.Columns.AutoFit
End If
With .Cells(.Rows.Count, iCol).End(xlUp).Offset(1)
If Target.Count = 1 Then
.Offset(0, 1) = Cells(Target.Row, 2) 'SAPID
End If
'.Offset(0, 1) = Cells(Target.Row, 2) 'SAPID
If Target.Count = 1 Then
.Offset(0, 2) = Cells(Target.Column) 'Field name
End If
'.Offset(0, 2) = Cells(Target.Column) 'Field name
.Value = sOldAddress
.Offset(0, 3).Value = vOldValue
If Target.Count = 1 Then
.Offset(0, 4).Value = Target.Value
End If
.Offset(0, 5) = Time
.Offset(0, 6) = Date
.Offset(0, 7) = Application.UserName
.Offset(0, 7).Borders(xlEdgeRight).LineStyle = xlContinuous
End With
.Protect Password:="Secret" 'comment to protect the "tracker tab"
End With
ErrorExit:
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
wActSheet.Activate
Exit Sub
ErrorHandler:
'any error handling you want
'Debug.Print "We have an error"
Resume ErrorExit
End Sub
Public Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
With Target
sOldAddress = .Address(external:=True)
If .Count > 1 Then
vOldValue = "Multiple Cell Select"
Else
vOldValue = .Value
End If
End With
End Sub
'Call Tracker' in the loop does not produce an error. In fact the code seems to execute and loops through all the files but it does not run the macro in each one it opens.

Copy row based on content and paste it in different sheets which are selected based on the content of the row

We've created a order sheet for all our machines, the main sheet is 'Order Sheet'.
And we're sending this sheet to the purchasing department at the end of the day.
When we run the macro to email the file, we wanted the macro to also copy each row to the specific machine worksheet. Eg. rows marked as 'Slicer' to go to the 'Slicer' sheet, 'blender' to 'blender', etc.
This is what I've got so far:
Sub PrintToNetwork()
ActiveWorkbook.Save
Range("A2:N25").Font.Size = 11
Dim OutApp As Object
Dim OutMail As Object
Dim answer As Integer
answer = MsgBox("Are you sure you want to Print & Send the sheet?", vbYesNo + vbQuestion, "Empty Sheet")
If answer = vbYes Then
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = ""
.CC = ""
.BCC = ""
.Subject = "Retail Order Sheet"
.Body = "Hi Andy, Please order."
.Attachments.Add ActiveWorkbook.FullName
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
Range("A1:N25").Select
ActiveSheet.PageSetup.PrintArea = "$A$1:$N$25"
oldprinter = Application.ActivePrinter
For i = 0 To 15
curNePrint = Format(i, "00")
On Error Resume Next
Application.ActivePrinter = "\\10.17.0.9\CCFN_Retail_MFP_BW on Ne" & curNePrint & ":"
Next i
ActiveWindow.Selection.PrintOut Copies:=1
Application.ActivePrinter = oldprinter
On Error GoTo 0
Else
End If
End Sub
Assuming the rows' location on the destination worksheet is determined by examining the same column as the one containing the worksheet names, something like the following might do the trick.
The DispatchRows sub scans prngWorksheetNames, looking for worksheets that exist by name.
You must call DispatchRows by passing it the range containing the worksheet names. For example, if the source worksheet names are on worksheet Summary, range C2:C50, you'd call DispatchRows ThisWorkbook.Worksheets("Summary").Range("C2:C50").
Option Explicit
'Copies entire rows to worksheets whose names are found within prngWorksheetNames.
'ASSUMPTION: on the destination worksheet, a copied row is appended at the lowest empty spot in the same column as prngWorksheetNames.
Public Sub DispatchRows(ByVal prngWorksheetNames As Excel.Range)
Dim lRow As Long
Dim rngWorksheetName As Excel.Range
Dim sDestWorksheetTabName As String
Dim oDestWs As Excel.Worksheet
Dim bScreenUpdating As Boolean
Dim bEnableEvents As Boolean
On Error GoTo errHandler
bScreenUpdating = Application.ScreenUpdating
bEnableEvents = Application.EnableEvents
Application.ScreenUpdating = False
Application.EnableEvents = False
For lRow = 1 To prngWorksheetNames.Rows.Count
Set rngWorksheetName = prngWorksheetNames.Cells(lRow, 1)
sDestWorksheetTabName = CStr(rngWorksheetName.Value)
If TryGetWorksheetByTabName(ThisWorkbook, sDestWorksheetTabName, oDestWs) Then
'Make sure there are no active autofilters on the destination worksheet, as they would typically interfere with the copy operation.
If oDestWs.FilterMode Then
oDestWs.ShowAllData
End If
'Copy and paste.
rngWorksheetName.EntireRow.Copy
oDestWs.Cells(oDestWs.Rows.Count, prngWorksheetNames.Column).End(xlUp).Offset(1).EntireRow.PasteSpecial xlPasteAll
End If
Next
Cleanup:
On Error Resume Next
Set rngWorksheetName = Nothing
Set oDestWs = Nothing
Application.CutCopyMode = False
Application.EnableEvents = bEnableEvents
Application.ScreenUpdating = bScreenUpdating
Exit Sub
errHandler:
MsgBox Err.Description, vbExclamation + vbOKOnly, "Error"
Resume Cleanup
End Sub
'Returns True, and a reference to the target worksheet, if worksheet psName is found by name on pwbkHost.
Public Function TryGetWorksheetByTabName(ByVal pwbkHost As Excel.Workbook, ByVal psName As String, ByRef pshtResult As Excel.Worksheet) As Boolean
Set pshtResult = Nothing
On Error Resume Next
Set pshtResult = pwbkHost.Worksheets(psName)
TryGetWorksheetByTabName = Not pshtResult Is Nothing
End Function
Here is very simple script to achieve what you want. Insert in your code appropriately, or call it from your macro. I tested this many times to make sure it works.
Sub CopyLines()
Dim mySheet
Dim LastRow As Long
Dim LastShtRow As Long
Dim j
LastRow = Sheets("Order Sheet").Cells(Rows.Count, 1).End(xlUp).Row
For j = 2 To LastRow Step 1
mySheet = Range("B" & j).Value
LastShtRow = Sheets(mySheet).Cells(Rows.Count, 1).End(xlUp).Row
Range("A" & j & ":" & "N" & j).Copy
Sheets(mySheet).Range("A" & LastShtRow + 1).PasteSpecial xlPasteValues
Next j
Application.CutCopyMode = False
End Sub

How to suppress excel large info on clipboard message

I am copying data from worksheet ws and am trying to paste just the values back to the original sheet, thus overwriting the original data with plain text. When I close the workbook I get an excel message telling me "There is a large amount of information on the clipboard. Do you want to be able to past this information into another program?" I will never want to do this. I don't want this message to not appear or assume the answer is "No".
Function FindPresenters(MyDate As Date, MyWS As String) As String
'MyDate is in format of 10/3/2016
'MyWS is the target worksheet to find MyDate
Dim GCell As Range
Dim xlApp As Object
Dim WB As Workbook
Dim WS As Worksheet
Dim MyLoop As Integer
Dim Found As Boolean
On Error GoTo ErrorHandler
Set xlApp = CreateObject("Excel.application") 'New Excel.Application
Application.ScreenUpdating = True
xlApp.Visible = True
Set WB = xlApp.Workbooks.Open ("Sched(Others).xlsx")
Set WS = WB.Worksheets("Oct 2016 Training Schedule")
With WS '.UsedRange
'.Cells.Select
.UsedRange.Select
.Cells.Copy
.Cells.PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False 'This should suppress msg, but doesn't
.Range("B2").Select
End With
WS.Activate
Set GCell = WS.Cells.Find(MyDate)
Found = False
For MyLoop = 1 To MaxDayItems 'Find the entrees for the month
Debug.Print GCell.Offset(MyLoop, 0).Text
If Not Found And InStr(1, GCell.Offset(MyLoop, 0).Text, "C.O.") > 0 Then
'Found data
Found = True
FindPresenters = GCell.Offset(MyLoop, 0).Text
MyLoop = MaxDayItems + 1 'Terminate searching
End If
Next MyLoop
Done:
Application.DisplayAlerts = False 'Tried this to suppress the message
WB.Close True 'This is where the Clipboard error appears
Application.DisplayAlerts = True
Application.ScreenUpdating = True
Set WS = Nothing
Set WB = Nothing
xlApp.Quit
Set xlApp = Nothing
Exit Function
'Error Handling section.
ErrorHandler:
...
GoTo Done
End Function
Because the cells you are copying belong to xlApp (a separate instance of Excel.Application) you will need to make xlApp.CutCopyMode equal false.
xlApp.CutCopyMode = False
I agree with Comintern's comment "You're only pasting values - just write them directly"
It appears that you are simple replacing all the formulas on the worksheet with their values. This can be achieved by simply like this:
WS.UsedRange.Value = WS.UsedRange.Value

error handler works only once in vba

I am trying to pull data from several workbooks which have different sheet names. I have created an array which contains all the possible sheet names. When data workbook opens and sheet name is not found the error handler works for the first time when loop runs again and pull the next array element, error handler doesn't work. It gives "Subscript out of range" error. Can anyone please elaborate what am I missing here? What I want is in case consecutive sheet names are not available in data workbook, code should go into for loop again and search for next sheet name.
Public strFileName As String
Public currentWB As Workbook
Public dataWB As Workbook
Sub GetData()
Dim strListSheet As String
Dim i As Integer
Dim VendorValue As String
Dim SheetNames() As Variant
Dim a As String
strListSheet = "Master"
Sheets(strListSheet).Select
Range("First_file").Select
SheetNames = Range("Sheet_Names")
'this is the main loop, we will open the files one by one and copy their data into the masterdata sheet
Set currentWB = ActiveWorkbook
Do While ActiveCell.Value <> ""
strFileName = ActiveCell.Offset(0, 1) & ActiveCell.Value
VendorValue = ActiveCell.Offset(0, 2)
Application.Workbooks.Open strFileName, UpdateLinks:=False, ReadOnly:=True
Set dataWB = ActiveWorkbook
For i = LBound(SheetNames, 1) To UBound(SheetNames, 1)
a = SheetNames(i, 1)
b = SheetNames(i, 2)
dataWB.Activate
On Error GoTo Handler:
ActiveWorkbook.Sheets(a).Select
Range("H5:H120,I5:I120,M5:M120,P5:P120,U5:X120").Select
Selection.Copy
currentWB.Activate
Sheets(VendorValue).Select
Range(b).Select
Selection.PasteSpecial xlPasteValues, xlPasteSpecialOperationNone
Application.CutCopyMode = False
Handler:
Next
dataWB.Close False
Sheets(strListSheet).Select
ActiveCell.Offset(1, 0).Select
Loop
Exit Sub
End Sub
You have to exit the error handler in order to reuse it. That is you need a Resume clause at the end of your error handler.
Check this site for more details.
I have moved the handler at the end of the sub and added a Resume.
Public strFileName As String
Public currentWB As Workbook
Public dataWB As Workbook
Sub GetData()
Dim strListSheet As String
Dim i As Integer
Dim VendorValue As String
Dim SheetNames() As Variant
Dim a As String
strListSheet = "Master"
Sheets(strListSheet).Select
Range("First_file").Select
SheetNames = Range("Sheet_Names")
'this is the main loop, we will open the files one by one and copy their data into the masterdata sheet
Set currentWB = ActiveWorkbook
Do While ActiveCell.Value <> ""
strFileName = ActiveCell.Offset(0, 1) & ActiveCell.Value
VendorValue = ActiveCell.Offset(0, 2)
Application.Workbooks.Open strFileName, UpdateLinks:=False, ReadOnly:=True
Set dataWB = ActiveWorkbook
For i = LBound(SheetNames, 1) To UBound(SheetNames, 1)
a = SheetNames(i, 1)
b = SheetNames(i, 2)
dataWB.Activate
On Error GoTo Handler:
ActiveWorkbook.Sheets(a).Select
Range("H5:H120,I5:I120,M5:M120,P5:P120,U5:X120").Select
Selection.Copy
currentWB.Activate
Sheets(VendorValue).Select
Range(b).Select
Selection.PasteSpecial xlPasteValues, xlPasteSpecialOperationNone
Application.CutCopyMode = False
Handler2:
Next
dataWB.Close False
Sheets(strListSheet).Select
ActiveCell.Offset(1, 0).Select
Loop
Exit Sub
Handler:
Resume Handler2
End Sub
I'd change approach like follows:
Dim mySht as Worksheet
a = SheetNames(i, 1)
Set mySht = GetSheet(dataWB, a)
If Not mySht Is Nothing Then
b = SheetNames(i, 2)
With mySht
.Range("H5:H120,I5:I120,M5:M120,P5:P120,U5:X120").Copy
currentWB.Sheets(VendorValue).Range(b).PasteSpecial xlPasteValues, xlPasteSpecialOperationNone
Application.CutCopyMode = False
End With
End If
Where I only showed the part that goes from a and b settings (included) to the Handler label (included, i.e. it has to disappear).
And you have to put this code in any module (also at the end of your Sub will do):
Function GetSheet(wb as Workbook, shtName as String)
On Error Resume Next
Set GetSheet = wb.Worksheet(shtName)
End Function
Finally the rest of your code can avoid a lot of Activate/Active/Select/Selection stuff in a similar manner
If all your files are in the same path, I think it's easier to use this:
Sub openOtherWorkbooks()
Dim folderPath As String, path As String
folderPath = "C:\Path\to\your\files"
path = folderPath & "\*.xlsm" 'xlsm as an example - could be xls* as well
Do While Filename <> ""
Filename = Dir()
If Filename <> ThisWorkbook.Name And Filename <> "" Then
Workbooks.Open folderPath & "\" & Filename
For i = 1 To Workbooks(Filename).Sheets.count
' do everything with every sheet of this file
Next i
Workbooks(Filename).Close False
End If
Filename = Dir(path)
Loop
End Sub
It's just opening every file, counting the sheets (beginning with 1) of the opened file and then there should be your code.
It's not exactly an answer to your On-Error-GoTo-thing with your handler.

Creating a loop to copy a result row from number of worksheets to a new worksheet

Good afternoon,
I am trying to read number of csv files and load them in a new workbook. Then created codes to find the largest number from each column (i.e. maximum value) and pasted in the bottom of each column. I have completed up to the stage of calcualting the largest value and pasting in the lastrow with the help of this forum.
Now I am trying to transfer them in a new worksheet that I created and named as result with my code. With previous suggestions I have figured out how to paste a specific range from one column to another worksheet with the following example:
Sub OneCell()
Sheets("Result").Range("E3:V3").Value = Sheets("HP5_1gs_120_2012.plt").Range("E3:V3").Value
End Sub
But not sure how can I loop this with my existing codes to read the last row where my max values are (highlighted in yellow in figure 1) and paste to the result sheet with the header from column E to the last available column and the rowname as the worksheet name. My data structure will be same for each worksheet for each run. And my start column is always column "E" but the end column (i.e. the last column) can be different for each run. THis is what I am getting really confused of how do I loop thorugh this. So for an example a simple dataset like below (Figure 1):
I am trying to achieve this (figure 2):
my main codes are as below:
Private Sub FilePath_Button_Click()
get_folder
End Sub
Private Sub Run_Button_Click()
load_file
End Sub
Public Sub get_folder()
Dim FolderName As String
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
On Error Resume Next
FolderName = .SelectedItems(1)
Err.Clear
On Error GoTo 0
End With
TextBox1.Text = FolderName
End Sub
Sub load_file()
Dim strFile As String
Dim ws As Worksheet
Dim test As String
Dim wb As Workbook
test = TextBox1.Text
strFile = Dir(Me.TextBox1.Text & "\*.csv")
Set wb = Workbooks.Add
'added workbook becomes the activeworkbook
With wb
Do While Len(strFile) > 0
Set ws = ActiveWorkbook.Sheets.Add
ws.Name = strFile
With ws.QueryTables.Add(Connection:= _
"TEXT;" & test & "\" & strFile, Destination:=Range("$A$1"))
.Name = strFile
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
strFile = Dir
Loop
End With
Application.DisplayAlerts = False
Worksheets("Sheet1").Delete
Worksheets("Sheet2").Delete
Worksheets("Sheet3").Delete
Application.DisplayAlerts = True
Dim ws1 As Worksheet
Dim ColNo As Long, lc As Long
Dim lastrow As Long
For Each ws1 In ActiveWorkbook.Worksheets
lastrow = Range("A1").End(xlDown).Row
lc = ws1.Cells(1, Columns.Count).End(xlToLeft).Column
For ColNo = 5 To lc
ws1.Cells(lastrow + 2, ColNo).Formula = "=MAX(" & Split(Cells(, ColNo).Address, "$")(1) & "1:" & Split(Cells(, ColNo).Address, "$")(1) & lastrow & ")"
Next ColNo
Next ws1
Dim ws2 As Worksheet
Set ws2 = Sheets.Add
Sheets.Add.Name = "Result"
MsgBox "Job Complete"
End Sub
Private Sub UserForm_Click()
End Sub
I hope I have managed to explain what I am trying to acheive and I would really appreciate any guidence with this. Thanks
Something like the below should do it. No doubt you will want to tweak bits but the general structure is there. I have commented what each block is doing - make sure you understand each line.
But normally for asking questions you should really really break the question down into its parts.
Like - "How do I loop through sheets", then "How do I find the last row of a sheet", then "How do I copy ranges" etc.
You would find that every single one of those has been asked before so in fact a little searching of Stackoverflow would be all that is needed.
Sub example()
Dim ws As Worksheet, dWs As Worksheet 'variables for ws enumerator and destination ws
Dim wb As Workbook 'variable to define the workbook context
Dim sRng As Range, dRng As Range 'variables for source range and destination range
Set wb = ActiveWorkbook
'Add the results sheet and assign our current row range
Set dWs = wb.Worksheets.Add
Set dRng = dWs.Cells(2, 1)
'Change the results sheet name (error if name exists so trap it)
On Error Resume Next
dWs.Name = "Result"
On Error GoTo 0
'Loop worksheets
For Each ws In wb.Worksheets
'Only work on the .csv sheet names
If ws.Name Like "*.csv" Then
'Find the row with the values on
Set sRng = ws.Cells(ws.Rows.Count, 4).End(xlUp)
'And set the range to be to the contiguous cells to the right
Set sRng = ws.Range(sRng, sRng.End(xlToRight))
'Add the sheet name to the results col A
dRng.Value = ws.Name
'Copy sRng to the output range
sRng.Copy dRng(1, 2)
'Increment output row to the next one
Set dRng = dRng(2, 1)
End If
Next ws
'Now just add the headers
For Each dRng In dWs.Range(dWs.Cells(1, 2), dWs.Cells(1, dWs.Cells.Find("*", , XlFindLookIn.xlFormulas, , XlSearchOrder.xlByColumns, xlPrevious).Column))
dRng.Value = "data " & dRng.Column - 1
Next
End Sub