error mismatch VBA - windows

enter image description hereI'm getting hard time figuring what is going on in my code. It keeps saying "run-time error:'13' ". How can I handle this error?
Dim ws As Worksheet
Dim rearr(), wrarr()
Dim fName As String
Dim rowno As Long, colno As Long, rec As Long
Dim cnt As Long, cnt2 As Long
Dim delim As String
'specify output sheet
Set ws = Worksheets("1.Locations")
'specify text file to read (.csv in this example)
fName = "C:\Users\HP\Desktop\names.csv"
'set text file delimiter
delim = "," 'for Tab delimiter use delim = Chr(9)
ifnum = FreeFile
'set start row/col for text data to be placed ("A1" in this example)
rowno = 3 'row 1
colno = 2 'col A
With ws
Open fName For Input Access Read As #ifnum
rec = 0
Do While Not EOF(ifnum)
Line Input #ifnum, tmpvar
rec = rec + 1
'Put whole record into array
ReDim Preserve rearr(1 To rec)
rearr(rec) = tmpvar
'Split fields into a second array
wrarr = Split(rearr(rec), delim)
cnt2 = UBound(wrarr)
'Write fields out to specified ws range, one row per record
For cnt = 0 To cnt2
ws.Cells(rowno, colno + cnt) = wrarr(cnt)
Next cnt
rowno = rowno + 1
Loop
Close #ifnum
End With

I have reproduced your error.
In your declarations, change
Dim wrarr()
to
Dim wrarr

Related

Count Items in file using VB

Kind of new to VBS. I'm trying to count the fields in the file and have this code.
Col()
Function Col()
Const FSpec = "C:\test.txt"
Const del = ","
dim fs : Set fs = CreateObject("Scripting.FileSystemObject")
dim f : Set f = fs.OpenTextFile(FSpec, 1)
Dim L, C
Do Until f.AtEndOfStream
L = f.ReadLine()
C = UBound(Split(L, del))
C = C +1
WScript.Echo "Items:", C
Loop
f.Close
End Function
It works however, I don't want to count the delim inside " ".
Here's file content:
1,"2,999",3
So basically, I'm getting 4 items for now but I wanted to get 3. Kind of stuck here.
For an example of my second suggestion, a very simple example could be something like this. Not saying it is perfect, but it illustrates the idea:
Dim WeAreInsideQuotes 'global flag
Function RemoveQuotedCommas(ByVal line)
Dim i
Dim result
Dim current
For i = 1 To Len(line)
current = Mid(line, i, 1) 'examine character
'check if we encountered a quote
If current = Chr(34) Then
WeAreInsideQuotes = Not WeAreInsideQuotes 'toggle flag
End If
'process the character
If Not (current = Chr(44) And WeAreInsideQuotes) Then 'skip if comma and insode quotes
result = result & current
End If
Next
RemoveQuotedCommas = result
End Function

Excel Sort By Numbers Macro

I use a macro to delete rows which doesnt containing numbers for my report.
This macro find critical path numbers and split them. In a1 column it delete the numbers which doesnt in the list.
This macro works fine. Beside that i want to sort a1 column by critical path number orders.
In this link I added what i want and my report file. There is a critical path text at the bottom in report file. When i click Düzenle macro delete rows but not sort by critical path number orders.
Thanks for your helps!
I do not like performing complex changes and deleting rows at the same time. If anything goes wrong, you have to restore the worksheet. I have introduced a new worksheet "Critical Path" and have copied to it everything required from worksheet "Revit KBK Sonuç" in the desired sequence.
I have described what I am doing and why within the macro. I hope it is all clear but ask if necessary.
Option Explicit
Sub ertert()
' I avoid literals within the code if I think those literals may change
' over time and/or if I think a name would make the code clearer.
Const ColLast As Long = 10
Const ColShtHdrLast As Long = 2
Const TableHdr1 As String = "Total Pressure Loss Calculations by Sections"
Dim ColCrnt As Long
Dim Section() As String
Dim CriticalPath As String
Dim InxSect As Long
Dim Rng As Range
Dim RowDestNext As Long
Dim RowSrcLast As Long
Dim RowTableHdr1 As Long
Dim wshtDest As Worksheet
Dim wshtSrc As Worksheet
Set wshtSrc = Worksheets("Revit KBK Sonuç")
Set wshtDest = Worksheets("Critical Path")
With wshtDest
.Cells.EntireRow.Delete
End With
' I only work on the ActiveWorksheet if the user is to select the
' target worksheet in this way. Code is easier to understand if
' With statements are used.
With wshtSrc
' Copy column widths
For ColCrnt = 1 To ColLast
wshtDest.Columns(ColCrnt).ColumnWidth = .Columns(ColCrnt).ColumnWidth
Next
' I avoid stringing commands together. The resultant code may be
' marginally faster but it takes longer to write and much longer
' to decipher when you return to the macro in 12 months.
' Extract critial path string and convert to array of Section numbers
RowSrcLast = .Cells(Rows.Count, "A").End(xlUp).Row
CriticalPath = .Cells(RowSrcLast, "A").Value
' Extract text before trailing total pressure loss
CriticalPath = Split(CriticalPath, ";")(0)
' Discard introductory text and trim spaces
CriticalPath = Trim(Split(CriticalPath, ":")(1))
Section = Split(CriticalPath, "-")
Set Rng = .Cells.Find(What:=TableHdr1)
If Rng Is Nothing Then
Call MsgBox("I am unable to find the row containing """ & _
TableHdr1 & """", vbOKOnly)
Exit Sub
End If
RowTableHdr1 = Rng.Row
' Copy header section of worksheet without buttons
.Range(.Cells(1, 1), .Cells(RowTableHdr1 - 1, ColShtHdrLast)).Copy _
Destination:=wshtDest.Cells(1, 1)
' Copy table header
.Range(.Cells(RowTableHdr1, 1), .Cells(RowTableHdr1 + 1, ColLast)).Copy _
Destination:=wshtDest.Cells(RowTableHdr1, 1)
RowDestNext = RowTableHdr1 + 2
' Copy rows for each section in critical path to destination worksheet
For InxSect = 0 To UBound(Section)
Set Rng = .Columns("A:A").Find(What:=Section(InxSect), LookAt:=xlWhole)
If Rng Is Nothing Then
Call MsgBox("I am unable to find the row(s) for Section" & _
Section(InxSect), vbOKOnly)
Else
Set Rng = Rng.MergeArea ' Expand to include all rows for section
' Copy all rows for section
Rng.EntireRow.Copy Destination:=wshtDest.Cells(RowDestNext, 1)
' Step output row number
RowDestNext = RowDestNext + Rng.Rows.Count
End If
Next
' Copy critical path row
.Rows(RowSrcLast).EntireRow.Copy Destination:=wshtDest.Cells(RowDestNext, 1)
RowDestNext = RowDestNext + 1
End With
' Add border at bottom of output table
With wshtDest
With .Range(.Cells(RowDestNext, 1), _
.Cells(RowDestNext, ColLast)).Borders(xlEdgeTop)
.LineStyle = xlContinuous
.Weight = xlMedium
.ColorIndex = 16
End With
End With
End Sub
New version of macro in response to request
Because the sections have different numbers of rows, no in situ sort is possible.
Version 1 solved this problem by copying required rows to a different worksheet. Version 2 solves this problem by copying them to a workarea below the original table but within the same worksheet. That is, a new table is built beneath the old.
Once the new table is complete, the old table is deleted to move the new table into the correct position.
Sub ertert()
Const ColLast As Long = 10
Const ColShtHdrLast As Long = 2
Const TableHdr1 As String = "Total Pressure Loss Calculations by Sections"
Dim ColCrnt As Long
Dim Section() As String
Dim CriticalPath As String
Dim InxSect As Long
Dim Rng As Range
Dim RowDestNext As Long
Dim RowDestStart As Long
Dim RowSrcLast As Long
Dim RowTableHdr1 As Long
Dim wsht As Worksheet
Set wsht = ActiveSheet
With wsht
' Extract critial path string and convert to array of Section numbers
RowSrcLast = .Cells(Rows.Count, "A").End(xlUp).Row
CriticalPath = .Cells(RowSrcLast, "A").Value
' Extract text before trailing total pressure loss
CriticalPath = Split(CriticalPath, ";")(0)
' Discard introductory text and trim spaces
CriticalPath = Trim(Split(CriticalPath, ":")(1))
Section = Split(CriticalPath, "-")
Set Rng = .Cells.Find(What:=TableHdr1)
If Rng Is Nothing Then
Call MsgBox("I am unable to find the row containing """ & _
TableHdr1 & """", vbOKOnly)
Exit Sub
End If
RowTableHdr1 = Rng.Row
' Because there is no fixed number of rows per section no in-situ sort is
' practical. Instead copy required rows in required section to destination
' area below existing area.
RowDestStart = RowSrcLast + 2
RowDestNext = RowDestStart
' Copy rows for each section in critical path to destination area
For InxSect = 0 To UBound(Section)
Set Rng = .Columns("A:A").Find(What:=Section(InxSect), LookAt:=xlWhole)
If Rng Is Nothing Then
Call MsgBox("I am unable to find the row(s) for Section" & _
Section(InxSect), vbOKOnly)
Else
Set Rng = Rng.MergeArea ' Expand to include all rows for section
' Copy all rows for section
Rng.EntireRow.Copy Destination:=.Cells(RowDestNext, 1)
' Step output row number
RowDestNext = RowDestNext + Rng.Rows.Count
End If
Next
' Copy critical path row
.Rows(RowSrcLast).EntireRow.Copy Destination:=.Cells(RowDestNext, 1)
RowDestNext = RowDestNext + 1
' Add border at bottom of output table
With .Range(.Cells(RowDestNext, 1), _
.Cells(RowDestNext, ColLast)).Borders(xlEdgeTop)
.LineStyle = xlContinuous
.Weight = xlMedium
.ColorIndex = 16
End With
' Now have new table on rows RowDestStart to RowDestNext-1.
' Delete rows RowTableHdr1+2 to RowDestStart-1 (old table) to
' move new table into desired position.
.Rows(RowTableHdr1 + 2 & ":" & RowDestStart - 1).EntireRow.Delete
End With
End Sub

Sort without moving formatting

I have an Excel table in which multiple rows are given different coloured backgrounds by VBA macros. These background colours should be locked to the rows. My problem is that when the table is sorted by one column or another the background colours move as the data is reordered.
Can I format in another way to stop this happening so that the cells remain locked?
The code I use to format is:
For Each Row In rng.Rows
If Condition Then
Row.Select
cIndex = ColourIndex(colour)
With Selection.Interior
.ColorIndex = cIndex
End With
End If
Next
An example of my table is like this:
EDIT: Extra Code
Sub Quota(ByVal Type As String)
Dim records As Long
Dim sht1 As Worksheet
Set sht1 = Worksheets("Sheet1")
Dim sht2 As Worksheet
Set sht2 = Worksheets("Sheet2")
records = sht1.Range("A1048576").End(xlUp).Row - 5
Dim rng As Range
Dim rngRowCount As Long
Dim rLastCell As Range
Dim i As Long
sht2.Activate
'Last used cell
Set rLastCell = sht2.Cells.Find(What:="*", After:=Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False)
'All used columns except 1st
Set rng = sht2.Range(Cells(2, 1), rLastCell)
rng.Select
rngRowCount = rng.Rows.CountLarge
For i = 1 To rngRowCount
Dim valueAs String
Dim colour As String
Dim VarX As Long
Dim maxValue As Long
value= sht2.Cells(i + 1, 1).Value
colour = sht2.Cells(i + 1, 2).Value
If Type = "A" Then
VarX = sht2.Cells(i + 1, 3).Value
ElseIf Type = "B" Then
VarX = sht2.Cells(i + 1, 5).Value
End If
maxValue = (records / 100) * VarX
ColourRows value, colour, maxValue
Next i
End Sub
Sub ColourRows(value As String, colour As String, maxValue As Long)
Dim sht1 As Worksheet
Set sht1 = Worksheets("Sheet1")
sht1.Activate
Dim rng As Range
Dim firstSixRowsOnwards As Range
Dim lastColumn As Long
Dim usedColumns As Range
Dim usedColumnsString As String
Dim highlightedColumns As Range
Dim rngDataRowCount As Long
Dim performancevalueAs String
Dim cIndex As Integer
Dim count As Long
count = 0
Dim rLastCell As Range
'End row
rngDataRowCount = sht1.Range("A1048576").End(xlUp).Row
'First 6 rows
Set firstSixRowsOnwards = sht1.Range("A6:XFD1048576")
'Last column
lastColumn = Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
'Used Range
Set rng = sht1.Range(Cells(1, 1), Cells(rngDataRowCount, lastColumn))
'Used Columns
Set usedColumns = sht1.Range(Cells(1, 1), Cells(1048576, lastColumn))
Set rng = Intersect(rng, firstSixRowsOnwards, usedColumns)
For Each Row In rng.Rows
compareValue= Cells(Row.Row, 5)).Value
If (InStr(1, value, compareValue, 1) Then
Dim rowNumber As Long
Row.Select
If count < maxValue Then
cIndex = ColourIndex(colour)
With Selection.Interior
.ColorIndex = cIndex
End With
count = count + 1
Else
cIndex = 3 'red
With Selection.Interior
.ColorIndex = cIndex
End With
End If
End If
Next
End Sub
I believe that if you select your data by column and then sort (instead of a row limited range) then formatting will follow.
EDIT:
If you want to lock the formatting then use conditional formatting that is based on row number, e.g. ROW() = x or ROW() = range of values...
Tested: Use conditional formatting by formula set rule such as =ROW()=3 make sure excel does not double quote it for you, apply this to the entire data range. Row 3 will then always be formatted as you set here.
Setting in vba
Sub test()
Range("A3").Select
With Range("A3")
.FormatConditions.Add Type:=xlExpression, Formula1:="=ROW()=3"
.FormatConditions(1).Interior.ColorIndex = 46
End With
End Sub
Can be done with CF, for example (top rule is >11):
Edit - I inadvertently left out one rule
the second down below uses =ROW($A1)=11:
Here we go:
In this case, what I would do it one of the two things:
Conditional formatting. Needs lot of logics and manual steps so let us leave it.
A macro: Whenever you sort the data, please fire the following function
Sub Option1()
Dim row As Range
Dim rowNum As Integer
Dim tRange As Range
'set range here: in your example, it is A2:D11
Set tRange = ActiveSheet.Range("A2:D11")
'clear colors
tRange.ClearFormats ' clears the previous format
rowNum = 1
For Each row In tRange.Rows
Select Case rowNum
Case 1, 2
row.Interior.Color = RGB(255, 255, 0) ' 1 and 2nd will be yellow
Case 3, 4
row.Interior.Color = 255 ' 3rd and 4th row will be red
Case 5, 6
row.Interior.Color = RGB(0, 0, 255) ' 5 and 6th row will be blue
Case Else
row.Interior.Color = RGB(0, 255, 0) '' all the bottom row would be a Green row
End Select
rowNum = rowNum + 1
Next row
End Sub
Does it help?

I want to read the last 400 lines from a txt file

I know how to do it in VB.Net but not an idea in vb6.
What I what to achieve is to avoid reading the whole file.
Is that possible?
You could open the file using Random access. Work your way backward a byte at a time, counting the number of carriage return line feed character pairs. Store each line in an array, or something similar, and when you've read your 400 lines, stop.
Cometbill has a good answer.
To open file for Random access:
Open filename For Random Access Read As #filenumber Len = reclength
To get the length of the file in Bytes:
FileLen(ByVal PathName As String) As Long
To read from Random access file:
Get [#]filenumber,<[recnumber]>,<varname>
IMPORTANT: the <varname> from the Get function must be a fixed length string Dim varname as String * 1, otherwise it will error out with Bad record length (Error 59) if the variable is declared as a variable length string like this Dim varname as String
EDIT:
Just wanted to point out that in Dim varname as String * 1 you are defining a fixed length string and the length is 1. This is if you wish to use the read-1-byte-backwards approach. If your file has fixed length records, there is no need to go 1 byte at a time, you can read a record at a time (don't forget to add 2 bytes for carriage return and new line feed). In the latter case, you would define Dim varname as String * X where X is the record length + 2. Then a simple loop going backwards 400 times or untill reaching the beginning of the file.
The following is my take on this. This is more efficient than the previous two answers if you have a very large file, since we don't have to store the entire file in memory.
Option Explicit
Private Sub Command_Click()
Dim asLines() As String
asLines() = LoadLastLinesInFile("C:\Program Files (x86)\VMware\VMware Workstation\open_source_licenses.txt", 400)
End Sub
Private Function LoadLastLinesInFile(ByRef the_sFileName As String, ByVal the_nLineCount As Long) As String()
Dim nFileNo As Integer
Dim asLines() As String
Dim asLinesCopy() As String
Dim bBufferWrapped As Boolean
Dim nLineNo As Long
Dim nLastLineNo As Long
Dim nNewLineNo As Long
Dim nErrNumber As Long
Dim sErrSource As String
Dim sErrDescription As String
On Error GoTo ErrorHandler
nFileNo = FreeFile
Open the_sFileName For Input As #nFileNo
On Error GoTo ErrorHandler_FileOpened
' Size our buffer to the number of specified lines.
ReDim asLines(0 To the_nLineCount - 1)
nLineNo = 0
' Read all lines until the end of the file.
Do Until EOF(nFileNo)
Line Input #nFileNo, asLines(nLineNo)
nLineNo = nLineNo + 1
' Check to see whether we have got to the end of the string array.
If nLineNo = the_nLineCount Then
' In which case, flag that we did so, and wrap back to the beginning.
bBufferWrapped = True
nLineNo = 0
End If
Loop
Close nFileNo
On Error GoTo ErrorHandler
' Were there more lines than we had array space?
If bBufferWrapped Then
' Create a new string array, and copy the bottom section of the previous array into it, followed
' by the top of the previous array.
ReDim asLinesCopy(0 To the_nLineCount - 1)
nLastLineNo = nLineNo
nNewLineNo = 0
For nLineNo = nLastLineNo + 1 To the_nLineCount - 1
asLinesCopy(nNewLineNo) = asLines(nLineNo)
nNewLineNo = nNewLineNo + 1
Next nLineNo
For nLineNo = 0 To nLastLineNo
asLinesCopy(nNewLineNo) = asLines(nLineNo)
nNewLineNo = nNewLineNo + 1
Next nLineNo
' Return the new array.
LoadLastLinesInFile = asLinesCopy()
Else
' Simply resize down the array, and return it.
ReDim Preserve asLines(0 To nLineNo)
LoadLastLinesInFile = asLines()
End If
Exit Function
ErrorHandler_FileOpened:
' If an error occurred whilst reading the file, we must ensure that the file is closed
' before reraising the error. We have to backup and restore the error object.
nErrNumber = Err.Number
sErrSource = Err.Source
sErrDescription = Err.Description
Close #nFileNo
Err.Raise nErrNumber, sErrSource, sErrDescription
ErrorHandler:
Err.Raise Err.Number, Err.Source, Err.Description
End Function

Read line-delimited data in VB6

So I have a number of text files that I'm trying to read with Visual Basic. They all have the same formatting:
[number of items in the file]
item 1
item 2
item 3
...etc.
What I'm trying to do is declare an array of the size of the integer in the first line, and then read each line into corresponding parts of the array (so item 1 would be array[0], item 2 would be array[1], etc. However, I'm not sure where to start on this. Any help would be appreciated.
Pretty basic stuff (no pun intended):
Dim F As Integer
Dim Count As Integer
Dim Items() As String
Dim I As Integer
F = FreeFile(0)
Open "data.txt" For Input As #F
Input #F, Count
ReDim Items(Count - 1)
For I = 0 To Count - 1
Line Input #F, Items(I)
Next
Close #F
try this for VB6
Dim file_id As Integer
Dim strline as string
Dim array_item() as string
'Open file
file_id = FreeFile
Open "C:\list.txt" For Input AS #file_id
Dim irow As Integer
irow = 0
'Loop through the file
Do Until EOF(file_id)
'read a line from a file
Line Input #file_id, strline
'Resize the array according to the line read from file
Redim Preserve array_item(irow)
'put the line into the array
array_item(irow) = strline
'move to the next row
irow = irow + 1
Loop
Close #file_id
The VB function you're looking for is "split":
http://www.vb-helper.com/howto_csv_to_array.html
Try this:
Dim FullText As String, l() As String
'''Open file for reading using Scripting Runtime. But you can use your methods
Dim FSO As Object, TS As Object
Set FSO = createbject("Scripting.FileSystemObject")
Set TS = createbject("Scripting.TextStream")
Set TS = FSO.OpenTextFile(FilePath)
TS.ReadLine 'Skip your first line. It isn't needed now.
'''Reading the contents to FullText and splitting to the array.
FullText = TS.ReadAll
l = Split(FullText, vbNewLine) '''the main trick
Splitting automatically resizes l() and stores all data.
Now the l() array has everything you want.

Resources