Language: VBA - MS Access
I am using User-Defined-Types (UDT) within my code.
I would like to be able determine which section of the UDT i'm loading data into based on a state variable. My first attempt was to use "With" statements nested into an "IF" statement. This doesn't work (I get a compiler error that says Else without if). Is there a way to make this work? or another way of going about using a state variable to determine which section of the UDT i'm loading?
Type MyOtherType
Name as String
Age as Integer
End Type
Type MyType
aMyOtherType() as MyOtherType
X as Integer
Y as Integer
Z as Integer
End Type
Sub QuestionableCode()
Dim UDT(0 To 0) as MyType
Dim State as String
ReDim Preserve UDT(0).X(0 to 0) as MyOtherType
ReDim Preserve UDT(0).Y(0 to 0) as MyOtherType
ReDim Preserve UDT(0).Z(0 to 0) as MyOtherType
State = "B"
If State = "A" Then
With UDT(0).X(0)
ElseIf State = "B" Then
With UDT(0).Y(0)
Else
With UDT(0).Z(0)
End If
.Name = "George"
.Age = 30
End With
End Sub
You can't work with With that way. The compiler doesn't allow this kind of conditionally nested code. Not with With, not with For, not with anything else.
You can, however, use a variable to determine which value you're going to use in your with:
Sub QuestionableCode()
Dim UDT(0 To 0) as MyType
Dim State as String
ReDim Preserve UDT(0).X(0 to 0) as MyOtherType
ReDim Preserve UDT(0).Y(0 to 0) as MyOtherType
ReDim Preserve UDT(0).Z(0 to 0) as MyOtherType
State = "B"
Dim myWithVariable
If State = "A" Then
myWithVariable = UDT(0).X(0)
ElseIf State = "B" Then
myWithVariable = UDT(0).Y(0)
Else
myWithVariable = UDT(0).Z(0)
End If
With myWithVariable
.Name = "George"
.Age = 30
End With
End Sub
Related
I'm looking to import all England and Wales Bank Holidays from https://www.gov.uk/bank-holidays.json and add them to a pre-created MS Access recordset (called "TestTable") using the MS Access VBA module. The code below opens and converts the json to a string, and then parses it using the JsonConverter.
This is where I seem to have hit a wall - I can't seem to get the right combo of Dictionaries and Collections to tell the VBA module the structure of the json file (I have no problem with creating a record in Access). After parsing the json, I'm getting one of two errors, most likely because what I think is supposed to be a dictionary (with {} brackets) and what I think is supposed to be a collection (with [] brackets) give me errors.
Option Explicit
Sub ImportBH()
Dim Parsed As Dictionary
Dim rsT As DAO.Recordset
Dim jsonStr As String
Dim dictionaryKey, var1 As Variant
Dim initialCollection As Collection
Set rsT = CurrentDb.OpenRecordset("TestTable")
Dim httpobject As Object
Set httpobject = CreateObject("MSXML2.XMLHTTP")
httpobject.Open "GET", "https://www.gov.uk/bank-holidays.json", False
httpobject.Send
jsonStr = httpobject.responsetext
Set Parsed = ParseJson(jsonStr) 'parse json data
If I now use the line:
For Each dictionaryKey In Parsed("england-and-wales")
Then at the end of the "item" function in JsonConverter, I get a Run-time error 438: Object doesn't support this property or method.
On the other hand, if I use the line:
For Each dictionaryKey In Parsed.Keys
Then it works (using the "Keys" function in JsonConverter), and when I hover over "Parsed.Keys", it gives me "england-and-wales". However, at the first line of the following code, I get a Run-time error 13: Type mismatch.
Set initialCollection = dictionaryKey("events")
With rsT
.AddNew
![Title] = var1("title")
![Datex] = var1("date")
![Notes] = var1("notes")
.Update
End With
Next
End Sub
I've tried the solutions (and others similar) in these links.
https://github.com/VBA-tools/VBA-Web/issues/134 - I'm aware this is for exporting json and not importing, but I thought the syntax might help, as Tim Hall has replied himself. Unfortunately, The ".Data" property doesn't appear or work for me :(
VBA-Json Parse Nested Json - When trying to apply this to the UK Bank Holidays json, I get Run-time error 13 again.
https://github.com/VBA-tools/VBA-Web/issues/329 - If I try, for example:
Debug.Print Parsed(dictionaryKey)
Then after then "item" function in JsonConverter, I get a Run-time error 449: Argument not optional.
https://github.com/VBA-tools/VBA-Web/issues/260 - I can't get to the stage to create a collection to use ".Count" to make this work.
If anyone has achieved this before in VBA, or might be able to offer a hand, it would be very much appreciated!
Start with learning how to read the json structure. You can paste the json string in a json viewer. You then get a nice view of the structure. In VBA JSON the [] denote a collection you can For Each over or access by index, and the {} denotes a dictionary you can For Each the keys of, or access by specific key.
If you put your json into a viewer you should be reading it something like as follows:
Excel version for use as template:
Accessing all items:
The following shows one way of emptying the entire json into an array (you could amend for adding to recordset?)
Option Explicit
Public Sub EmptyJsonIntoArray()
Dim json As Object, r As Long, c As Long, results(), counter As Long
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://www.gov.uk/bank-holidays.json", False
.Send
Set json = JsonConverter.ParseJson(.responsetext) 'dictionary with 3 keys
End With
Dim key As Variant, innerKey As Variant, col As Collection
Dim division As String, headers(), item As Object, arr()
arr = json.keys
headers = json(arr(LBound(arr)))("events").item(1).keys 'take first innermost dictionary keys as headers for output
'oversize array as number of events can vary by division
ReDim results(1 To 1000, 1 To UBound(headers) + 2) '4 is the number of keys for each event level dictionary. +1 so can have _
division included as first column in output and +1 to move from 0 based headers array to 1 based results
r = 1 'leave first row for headers
results(1, 1) = "Division"
For c = LBound(headers) To UBound(headers)
results(1, c + 2) = headers(c) 'write out rest of headers to first row
Next
For Each key In json.keys 'england-and-wales etc. division
division = key
For Each item In json(division)("events") 'variable number of events dictionaries within collection
r = r + 1: c = 2 'create a new row for event output. Set column to 2 (as position 1 will be occupied by division
results(r, 1) = division
For Each innerKey In item.keys 'write out innermost dictionary values into row of array
results(r, c) = item(innerKey)
c = c + 1
Next
Next
Next
'transpose array so can redim preserve the number of rows (now number of columns) to only required number based on current value of r
results = Application.Transpose(results)
ReDim Preserve results(1 To UBound(headers) + 2, 1 To r)
results = Application.Transpose(results) 'transpose array back
'STOP '<== View array
End Sub
Sample of results contents:
Access:
From feedback by OP. With Access there is no Application.Transpose. Instead array can be passed to the following functionsource. However, the array must then be 0 based that is passed.
Public Function TransposeArray(myarray As Variant) As Variant
Dim X As Long
Dim Y As Long
Dim Xupper As Long
Dim Yupper As Long
Dim tempArray As Variant
Xupper = UBound(myarray, 2)
Yupper = UBound(myarray, 1)
ReDim tempArray(Xupper, Yupper)
For X = 0 To Xupper
For Y = 0 To Yupper
tempArray(X, Y) = myarray(Y, X)
Next Y
Next X
TransposeArray = tempArray
End Function
Access version as appended by OP:
In addition to TransposeArray above (edited below to work in this case), here's the full code for Access:
Option Compare Database
Option Explicit
Public Sub UpdateBankHolidays()
Dim dbs As DAO.Database
Dim tBH As Recordset
Dim i, r, c As Long
Set dbs = CurrentDb
'Set recordset variable as existing table (in this case, called "z_BankHolidays")
Set tBH = dbs.OpenRecordset("z_BankHolidays")
'Download and parse json
Dim json As Object, results(), counter As Long
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://www.gov.uk/bank-holidays.json", False
.Send
Set json = ParseJson(.responsetext) 'dictionary with 3 keys
End With
Dim key As Variant, innerKey As Variant, col As Collection
Dim division As String, headers(), item As Object, arr()
arr = json.Keys
headers = json(arr(LBound(arr)))("events").item(1).Keys 'take first innermost dictionary keys as headers for output
'oversize array as number of events can vary by division
ReDim results(1 To 1000, 1 To UBound(headers) + 2) '4 is the number of keys for each event level dictionary. +1 so can have _
division included as first column in output and +1 to move from 0 based headers array to 1 based results
r = 1 'leave first row for headers
results(1, 1) = "Division"
For c = LBound(headers) To UBound(headers)
results(1, c + 2) = headers(c) 'write out rest of headers to first row
Next
For Each key In json.Keys 'england-and-wales etc. division
division = key
For Each item In json(division)("events") 'variable number of events dictionaries within collection
r = r + 1: c = 2 'create a new row for event output. Set column to 2 (as position 1 will be occupied by division
results(r, 1) = division
For Each innerKey In item.Keys 'write out innermost dictionary values into row of array
results(r, c) = item(innerKey)
c = c + 1
Next
Next
Next
'transpose array so can redim preserve the number of rows (now number of columns) to only required number based on current value of r
results = TransposeArray(results)
ReDim Preserve results(0 To UBound(results), 0 To r)
results = TransposeArray(results) 'transpose array back
'Clear all existing bank holidays from recordset
dbs.Execute "DELETE * FROM " & tBH.Name & ";"
'Insert array results into tBH recordset, transforming the date into a date value using a dd/mmm/yyyy format (in the array they are currently yyyy-mm-dd)
For i = 1 To r
If results(i, 1) = "england-and-wales" Then
dbs.Execute " INSERT INTO " & tBH.Name & " " _
& "(Title,Holiday,Notes) VALUES " _
& "('" & results(i, 2) & "', " & _
"'" & DateValue(Right(results(i, 3), 2) & "/" & Format("20/" & Mid(results(i, 3), 6, 2) & "/2000", "mmm") & "/" & Left(results(i, 3), 4)) & "', " & _
"'" & results(i, 4) & "'" & _
");"
End If
Next
'Finish
MsgBox "Bank Holidays updated."
End Sub
It's also worth noting that I (OP) had to change X and Y in the TransposeArray to start from 1, not 0 (even though, as noted above and in comments, subsequently redimming it must be based at 0). I.e.:
Public Function TransposeArray(myarray As Variant) As Variant
Dim X As Long
Dim Y As Long
Dim Xupper As Long
Dim Yupper As Long
Dim tempArray As Variant
Xupper = UBound(myarray, 2)
Yupper = UBound(myarray, 1)
ReDim tempArray(Xupper, Yupper)
For X = 1 To Xupper
For Y = 1 To Yupper
tempArray(X, Y) = myarray(Y, X)
Next Y
Next X
TransposeArray = tempArray
End Function
I have a dynamic array that I want to append values to. The number of values to be appended is not fixed
I was trying to do something like this:
Dim array() As Integer
ReDim Preserve array(UBound(array)+1)
bulkJob(UBound(array) + 1) = Me.ID
I get subscript out of range error at ReDim Preserve array(UBound(array)+1). Is there a way to do this?
Not quite clear what you are trying to do, but this could get you some ideas:
Public Function BuildJobs(Id As Integer)
Static bulkJob() As Integer
Dim Upper As Integer
On Error Resume Next
Upper = UBound(bulkJob) + 1
On Error GoTo 0
ReDim Preserve bulkJob(Upper)
' Fill in value.
bulkJob(Upper) = Id
' Do something.
Debug.Print UBound(bulkJob), bulkJob(Upper)
End Function
"Restart" the array like this:
ReDim bulkJob(0)
bulkJob(0) = 0
have been googling around for a code to extract tables from emails and am trying to adapt the codes by changing early binding to late binding.
However, the code seems to bug out at the objHTML.body.innerHTML = objMailItem.HTMLBody line.
Code seems to run alright when used in Excel but bugs out when I run on outlook vba.
any help to point me in the right direction would be appreciated!
Public Function ExtractOutlookTables(objMailItem As Object) As Object
Dim vTable As Variant
Dim objHTML As Object: Set objHTML = CreateObject("htmlFile")
Dim objEleCol As Object
objHTML.Body.innerHTML = objMailItem.HTMLBody ' <<error line>>
With objHTML
objHTML.Body.innerHTML = objMailItem.HTMLBody
Set objEleCol = .getElementsByTagName("table")
End With
'import in Excel
Dim x As Long, y As Long
For x = 0 To objEleCol(0).Rows.Length - 1
For y = 0 To objEleCol(0).Rows(x).Cells.Length - 1
vTable(x, y) = objEleCol(0).Rows(x).Cells(y).innerText
Next y
Next x
ErrorHandler:
Set objHTML = Nothing: Set objEleCol = Nothing
End Function
''
' Function that returns a dictionary of arrays of strings, each representing a table in the email; key = 0 represents the most recent table
' #param objMailItem object representing an Outlook Mail Item object
' #return Dictionary of arrays of strings where each key represents the index of the table (0 being the most recent table)
' #remarks Please note that index 0 = table in the most recent email conversation
' #see none
Public Function fnc_ExtractTablesFromMailItem(objMailItem As Object) As Object
Dim objHTMLDoc As Object: Set objHTMLDoc = CreateObject("HTMLFile")
Dim dicTables As Object: Set dicTables = CreateObject("scripting.Dictionary")
Dim arrTable() As String
Dim objTable As Object
Dim lngRow As Long
Dim lngCol As Long
Dim intCounter As Integer: intCounter = 0
objHTMLDoc.body.innerHTML = objMailItem.htmlbody
' Loop through each table in email
For Each objTable In objHTMLDoc.getElementsByTagName("table")
ReDim arrTable(objTable.Rows.Length - 1, objTable.Rows(1).Cells.Length - 1)
For lngRow = 0 To objTable.Rows.Length - 1
Set rw = objTable.Rows(lngRow)
For lngCol = 0 To rw.Cells.Length - 1
' Ignore any problems with merged cells etc
On Error Resume Next
arrTable(lngRow, lngCol) = rw.Cells(lngCol).innerText ' Store each table in 1 array
On Error GoTo 0
Next lngCol
Next lngRow
dicTables(intCounter) = arrTable ' Store each array as a dictionary item
intCounter = intCounter + 1
Next objTable
Set fnc_ExtractTablesFromMailItem = dicTables
' Garbage collection
Set dicTables = Nothing: Set objTable = Nothing: Set objHTMLDoc = Nothing
End Function
The problem seems to be in the code that is calling the function. You should post that code.
If the only thing that you actual want from objMailItem is it's HTMLBody then objMailItem As Object should be removed from function signature should and replaced with HTMLBody as String.
You must be missing a couple of lines of code; because vTablewas never allocated and will throw a type mismatch error the way the function is written.
You should also wrap your test whether objEleCol is Nothing before you try and use it.
Here I pass the MailItem to fnc_ExtractTablesFromMailItem from Application_ItemSend to in Outlook. There are no errors.
The Application_NewMail and Application_NewMailEx events do not recieve MailItems as parameters. How are you retrieving the MailItem that you are passing into your function?
I am pulling out my hair trying to parse data or edit into a msgraph series collection.
I get error 438 - object does not support this property or method.
I can manipulate other properties that the object has such as ChartTitle.Font.Size but not the seriescollection.
Intellisencing is not working wth this object which leads me to susspect that I have not set a particular reference.
Sections of the code is below.
The main routine gets the object:
strReportName = "Security Selection"
strChartName = "MACD_Chart"
DoCmd.OpenReport strReportName, acViewDesign
Set rptMACD = Reports(strReportName)
Set chartMACD = rptMACD(strChartName)
A data recordset is built then all of it is passed into the subroutine:
Call UpdateChart(chartMACD, rstMACD)
Public Sub UpdateChart(chartPlot As Object, rstChart As ADODB.Recordset)
'FUNCTION:
' a chart object is passed into the routine,
' source data is update to the recordset being passed in.
Dim lngType As Long
Dim i, j, iFieldCount As Integer
Dim rst As Recordset
Dim arXValues() As Date
Dim arValues() As Double
Dim strChartName, strYAxis, strXAxis As String
Dim ChrtCollection As ChartObjects
Dim colmCount As Integer
chartPlot.RowSourceType = "Table/Query"
'get number of columns in chart table/Query
iFieldCount = rstChart.Fields.Count
With chartPlot
'change chart data to arrays of data from recordset
.Activate
j = 0
rstChart.MoveFirst
Do While Not rstChart.EOF
j = j + 1
ReDim Preserve arXValues(1 To j)
arXValues(j) = rstChart.Fields("Date").Value
rstChart.MoveNext
Loop
For i = 1 To iFieldCount - 1 'Date is first field
j = 0
rstChart.MoveFirst
Do While Not rstChart.EOF 'get next array of data
j = j + 1
ReDim Preserve arValues(1 To j)
arValues(j) = rstChart.Fields(i + 1).Value
rstChart.MoveNext
Loop
.SeriesCollection(i).Name = rstChart.Fields(i + 1).Name
.SeriesCollection(1).XValues = arXValues
.SeriesCollection(i).Values = arValues
Next i
end sub
I've tried many things and now I'm totally confused. I've also been trying to parse in recordsets (which is my preference) but i'll take anything at the moment.
Before continuing: I recommend setting the Chart's Rowsource property to a query that returns the data you want and then Requerying the Chart. This is WAY easier than the following.
You are getting the Error 438 because Name, XValues, Values are not properties of the Series Object. MSDN Info
That being said, here is a go at your method and some recommendations for doing it that way. The SeriesCollection doesn't contain the values associated with MSGraph points like it does in Excel. You need to edit the data in the DataSheet, which is VERY finicky. A reference to the Microsoft Graph Library must be included. This was tested to work with my database. Microsoft Graph MSDN info
DAO
Public Sub testing()
Dim rstChart As Recordset
Dim seri As Object, fld As Field
Dim app As Graph.Chart
chartPlot.SetFocus
Set app = chartPlot.Object
Set rstChart = CurrentDb.OpenRecordset("SELECT DateTime, ASIMeasured FROM Surv_ASI WHERE CycleID = 2 ORDER BY DateTime")
app.Application.DataSheet.Range("00:AA1000").Clear
With rstChart
For Each fld In .Fields
app.Application.DataSheet.Range("a1:AA1").Cells(0, fld.OrdinalPosition) = fld.Name
Next
Do While Not .EOF
For Each fld In .Fields
app.Application.DataSheet.Range("a2:AA1000").Cells(.AbsolutePosition, fld.OrdinalPosition).Value = fld
Next
.MoveNext
Loop
End With
app.Refresh
End Sub
ADO (Assuming rstChart is already a valid ADODB.Recordset)
Public Sub testing()
Dim app As Graph.Chart, i As Integer
chartPlot.SetFocus
Set app = chartPlot.Object
app.Application.DataSheet.Range("00:AA1000").Clear
With rstChart
.MoveFirst 'Since I don't know where it was left off before this procedure.
For i = 0 To .Fields.Count - 1
app.Application.DataSheet.Range("a1:AA1").Cells(0, i) = .Fields(i).Name
Next
Do While Not .EOF
For i = 0 To .Fields.Count - 1
app.Application.DataSheet.Range("a2:AA1000").Cells(.AbsolutePosition, i).Value = .Fields(i)
Next
.MoveNext
Loop
End With
app.Refresh
End Sub
Some notes about my changes:
1. I prefer having my With point to the Recordset being cycled, instead of the Object being operated on, especially since more calls are made to the Recordset's properties in your procedure.
2. You don't need to specify the variable to which a Next applies (Next i). Just put Next.
3. Please pick my answer if it helped :)
So I was wondering, how can I return multiple values from a function, sub or type in VBA?
I've got this main sub which is supposed to collect data from several functions, but a function can only return one value it seems. So how can I return multiple ones to a sub?
You might want want to rethink the structure of you application, if you really, really want one method to return multiple values.
Either break things apart, so distinct methods return distinct values, or figure out a logical grouping and build an object to hold that data that can in turn be returned.
' this is the VB6/VBA equivalent of a struct
' data, no methods
Private Type settings
root As String
path As String
name_first As String
name_last As String
overwrite_prompt As Boolean
End Type
Public Sub Main()
Dim mySettings As settings
mySettings = getSettings()
End Sub
' if you want this to be public, you're better off with a class instead of a User-Defined-Type (UDT)
Private Function getSettings() As settings
Dim sets As settings
With sets ' retrieve values here
.root = "foo"
.path = "bar"
.name_first = "Don"
.name_last = "Knuth"
.overwrite_prompt = False
End With
' return a single struct, vb6/vba-style
getSettings = sets
End Function
You could try returning a VBA Collection.
As long as you dealing with pair values, like "Version=1.31", you could store the identifier as a key ("Version") and the actual value (1.31) as the item itself.
Dim c As New Collection
Dim item as Variant
Dim key as String
key = "Version"
item = 1.31
c.Add item, key
'Then return c
Accessing the values after that it's a breeze:
c.Item("Version") 'Returns 1.31
or
c("Version") '.Item is the default member
Does it make sense?
Ideas :
Use pass by reference (ByRef)
Build a User Defined Type to hold the stuff you want to return, and return that.
Similar to 2 - build a class to represent the information returned, and return objects of that class...
You can also use a variant array as the return result to return a sequence of arbitrary values:
Function f(i As Integer, s As String) As Variant()
f = Array(i + 1, "ate my " + s, Array(1#, 2#, 3#))
End Function
Sub test()
result = f(2, "hat")
i1 = result(0)
s1 = result(1)
a1 = result(2)
End Sub
Ugly and bug prone because your caller needs to know what's being returned to use the result, but occasionally useful nonetheless.
A function returns one value, but it can "output" any number of values. A sample code:
Function Test (ByVal Input1 As Integer, ByVal Input2 As Integer, _
ByRef Output1 As Integer, ByRef Output2 As Integer) As Integer
Output1 = Input1 + Input2
Output2 = Input1 - Input2
Test = Output1 + Output2
End Function
Sub Test2()
Dim Ret As Integer, Input1 As Integer, Input2 As Integer, _
Output1 As integer, Output2 As Integer
Input1 = 1
Input2 = 2
Ret = Test(Input1, Input2, Output1, Output2)
Sheet1.Range("A1") = Ret ' 2
Sheet1.Range("A2") = Output1 ' 3
Sheet1.Range("A3") = Output2 '-1
End Sub
you can return 2 or more values to a function in VBA or any other visual basic stuff but you need to use the pointer method called Byref. See my example below. I will make a function to add and subtract 2 values say 5,6
sub Macro1
' now you call the function this way
dim o1 as integer, o2 as integer
AddSubtract 5, 6, o1, o2
msgbox o2
msgbox o1
end sub
function AddSubtract(a as integer, b as integer, ByRef sum as integer, ByRef dif as integer)
sum = a + b
dif = b - 1
end function
Not elegant, but if you don't use your method overlappingly you can also use global variables, defined by the Public statement at the beginning of your code, before the Subs.
You have to be cautious though, once you change a public value, it will be held throughout your code in all Subs and Functions.
I always approach returning more than one result from a function by always returning an ArrayList. By using an ArrayList I can return only one item, consisting of many multiple values, mixing between Strings and Integers.
Once I have the ArrayList returned in my main sub, I simply use ArrayList.Item(i).ToString where i is the index of the value I want to return from the ArrayList
An example:
Public Function Set_Database_Path()
Dim Result As ArrayList = New ArrayList
Dim fd As OpenFileDialog = New OpenFileDialog()
fd.Title = "Open File Dialog"
fd.InitialDirectory = "C:\"
fd.RestoreDirectory = True
fd.Filter = "All files (*.*)|*.*|All files (*.*)|*.*"
fd.FilterIndex = 2
fd.Multiselect = False
If fd.ShowDialog() = DialogResult.OK Then
Dim Database_Location = Path.GetFullPath(fd.FileName)
Dim Database_Connection_Var = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=""" & Database_Location & """"
Result.Add(Database_Connection_Var)
Result.Add(Database_Location)
Return (Result)
Else
Return (Nothing)
End If
End Function
And then call the Function like this:
Private Sub Main_Load()
Dim PathArray As ArrayList
PathArray = Set_Database_Path()
My.Settings.Database_Connection_String = PathArray.Item(0).ToString
My.Settings.FilePath = PathArray.Item(1).ToString
My.Settings.Save()
End Sub
you could connect all the data you need from the file to a single string, and in the excel sheet seperate it with text to column.
here is an example i did for same issue, enjoy:
Sub CP()
Dim ToolFile As String
Cells(3, 2).Select
For i = 0 To 5
r = ActiveCell.Row
ToolFile = Cells(r, 7).Value
On Error Resume Next
ActiveCell.Value = CP_getdatta(ToolFile)
'seperate data by "-"
Selection.TextToColumns Destination:=Range("C3"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=True, OtherChar _
:="-", FieldInfo:=Array(Array(1, 1), Array(2, 1)), TrailingMinusNumbers:=True
Cells(r + 1, 2).Select
Next
End Sub
Function CP_getdatta(ToolFile As String) As String
Workbooks.Open Filename:=ToolFile, UpdateLinks:=False, ReadOnly:=True
Range("A56000").Select
Selection.End(xlUp).Select
x = CStr(ActiveCell.Value)
ActiveCell.Offset(0, 20).Select
Selection.End(xlToLeft).Select
While IsNumeric(ActiveCell.Value) = False
ActiveCell.Offset(0, -1).Select
Wend
' combine data to 1 string
CP_getdatta = CStr(x & "-" & ActiveCell.Value)
ActiveWindow.Close False
End Function