Excel VBA Macro No Longer Works (Possible issue with http.Send) - vba

I have a little Excel VBA macro that retrieves the stock value for a given company on a given day. The company is specified by passing in their stock symbol ("AZO" for AutoZone, "WMT" for Wal-Mart, etc.), and the date is an actual date value retrieved from an adjacent cell.
It has been working beautifully for 2.5 years, but this week it just stopped working, even though I didn't change anything whatsoever. Where the macro should be returning a value, now it's just returning #VALUE!. When I step through the code, everything is working fine until I get to the .Send(), where it just stops (no error messages or hints as to what went wrong; it just completely stops as if execution were finished). I tried adding an On Error clause but it doesn't get hit. Note: I'm thinking it doesn't make a difference, but originally I had http.Send with no parentheses, but I saw a lot of examples with ("") so I added that but it appears to not have an effect.
My VBA experience is very limited, so I was hoping someone would be able to point me in the right direction.
CODE:
Function StockQuote(strTicker As String, Optional dtDate As Variant)
' Date is optional - if omitted, use today. If value is not a date, throw error.
If IsMissing(dtDate) Then
dtDate = Date
Else
If Not (IsDate(dtDate)) Then
StockQuote = CVErr(xlErrNum)
End If
End If
Dim dtPrevDate As Date
Dim strURL As String, strCSV As String, strRows() As String, strColumns() As String
Dim dbClose As Double
dtPrevDate = dtDate - 7
' Compile the request URL with start date and end date
strURL = "http://ichart.finance.yahoo.com/table.csv?s=" & strTicker & _
"&a=" & Month(dtPrevDate) - 1 & _
"&b=" & Day(dtPrevDate) & _
"&c=" & Year(dtPrevDate) & _
"&d=" & Month(dtDate) - 1 & _
"&e=" & Day(dtDate) & _
"&f=" & Year(dtDate) & _
"&g=d&ignore=.csv"
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", strURL, False
http.Send ("")
strCSV = http.responseText
' The most recent information is in row 2, just below the table headings.
' The price close is the 5th entry
strRows() = Split(strCSV, Chr(10)) ' split the CSV into rows
strColumns = Split(strRows(1), ",") ' split the relevant row into columns. 1 means 2nd row, starting at index 0
dbClose = strColumns(4) ' 4 means: 5th position, starting at index 0
StockQuote = dbClose
Set http = Nothing
End Function

Ran into this same issue today with VBA code that has been working fine for many years. Thanks to this post, not only was I able to get it working again by using https. But I may know the underlying cause as well.
Believe the underlying cause may be perhaps finance.yahoo.com has enabled HSTS. This would mean that once the site is visited using https. The use of https will be enforced for all future requests.
HTTP Strict Transport Security
https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security

Related

String Variable inside Single Quotes in Another String Variable Not Expanding - VBA

I'm trying to build quite a complicated URL String in VBA and I'm having troule escaping everything correctly. I managed to get the URL to work, but now I'm trying to "variablize" the importart parts and can't understand the issue (VBA doesn't exactly give detailed errors either).
Here is a working and non-working example URL:
Dim URL As STring, Client As String
Client = "AClientName"
URL = "http://URL?filter={'mode':'cli','client':'AClientName'}" ' This Works
URL = "http://URL?filter={'mode':'cli','client':' & CLIENT & '}" ' This Fails to Open
You're just missing the a close and open quote around the variable.
If you debug.print, you can see that it's interpreting your & and Client as just another part of the string instead of concatenating it as a variable.
In:
Debug.Print "http://URL?filter={'mode':'cli','client':'AClientName'}"
Out:
http://URL?filter={'mode':'cli','client':'AClientName'}
This works because there's no escaping the string or concatenation needed.
You can see here that & CLIENT & are part of the string.
In:
Debug.Print "http://URL?filter={'mode':'cli','client':' & CLIENT & '}"
Out:
http://URL?filter={'mode':'cli','client':' & CLIENT & '}
To get the proper string with the variable use this.
In:
Debug.Print "http://URL?filter={'mode':'cli','client':'" & Client & "'}"
Out:
http://URL?filter={'mode':'cli','client':'AClientName'}

VBA dynamic dates inside an API URL

I have an API that I want to update dynamically so that the user can enter a start date and an end date on a spreadsheet and my macro will pull back data for that particular date range.
The issue I'm having is that within the API URL the StartDate and EndDate parameters must be in the format yyyy-mm-dd as a string.
I've tried URL = "https:// ...&StartDate = Format(Date(),"yyyy-mm-dd") & EndDate=Format(Date(),"yyyy-mm-dd")&..." (the ... is for the things before and after the URL).
An example of the type of URL I'm looking at is:
https://www.googleapis.com/analytics/v3/data/ga?ids=ga:12345&startdate=2008-10-01&end-date=2008-10-31&metrics=ga:sessions,ga:bounces
I've also played around with adding in extra quotes within the URL string but I can't seem to get it to work.
I keep getting told that the dates aren't being recognised and therefore I can only get the code to run if I hardcode dates.
Any suggestions?
I noticed a few issues in the code posted. The & is the concatenation operator in VBA. You need to enclose that in "" to make sure you are returning the ampersand as a string, and not joining strings together.
I've added some sample code which hopefully illustrates the idea and get's you back up and running. The code should print out True if the createdURL and testURL are equal, or False if not.
Code
Option Explicit
Public Sub FormatExample()
'This is the example provided
Dim testURL As String
testURL = "https://www.googleapis.com/analytics/v3/data/ga?ids=ga:12345&" & _
"startdate=2008-10-01&end-date=2008-10-31&metrics=ga:sessions,ga:bounces"
'This is a built string example
Dim createdURL As String
createdURL = "https://www.googleapis.com/analytics/v3/data/ga?ids=ga:12345" & _
"&startdate=" & Format(#10/1/2008#, "yyyy-mm-dd") & _
"&end-date=" & Format(#10/31/2008#, "yyyy-mm-dd") & _
"&metrics=ga:sessions,ga:bounces"
'Print out if they are equal
Debug.Print createdURL = testURL
End Sub

SQL query via macro / VBA, 64-bit MS Office users get, what looks like credentials prompt window, but no such for 32-bit MS Office users

I have a simple SQL query (below) that I run via a macro in Excel workbook. It works fine on MS Office 32-bit as well as 64-bit, however, for 64-bit Office users a pop-up window (below) appears in the middle (on the .Refresh line). It is enough to just press "OK" and the macro continues and fetches the data correctly, however, I would like to avoid this pop-up window if possible and/or understand why this is happening, please?
Query:
Sub Run_Query( _
ByRef SQL_Data_rng As Range, _
ByRef Conn_str As String, _
ByRef SQL_str As String)
With ws1.QueryTables.Add( _
Connection:="" & Conn_str & "", _
Destination:=SQL_Data_rng, _
Sql:=SQL_str)
.BackgroundQuery = False
.Refresh
End With
End Sub
As Conn_str is already a string, you don't need to quote it (actually: shouldn't quote it):
Connection:= Conn_str, ...
OK, I think I found the cause of the problem. There was a mistake deeper in my code that I didn’t mention. I'm going to post my findings here, hopefully it will help someone in the future.
I store my Connection and SQL query info in a worksheet and to get these into a string I'm using a small function.
Function BuildStr(Rng As Range) As String
Dim Sub_Str As Range
For Each Sub_Str In Rng
BuildStr = BuildStr & Sub_Str & vbNewLine
Next Sub_Str
End Function
The & vbNewLine is there to ensure SELECT, FROM, WHERE, etc. statements in my SQL string start from new lines (otherwise no dice) and it also makes it easier to read the query when occasionally printed out.
But looks like it should not be used in the Connection string.
So in short, the connection string should look like this:
OLEDB;DRIVER=SQL Server;SERVER=SVR_name;Database=DB_name;Trusted_Connection=Yes
And not like this:
OLEDB; & VbNewLine & DRIVER=SQL Server; & VbNewLine & SERVER=SVR_name; & VbNewLine & Database=DB_name; & VbNewLine & Trusted_Connection=Yes
I am yet to understand why this isn't an issue on 32-bit Office, but most importantly I got rid of the annoying pop-up window (and learned something I didn't know).
Thanks,
J.

Inserting data to other xls workbook via ADO & SQL – Data type error

I am building a quite complex UserForm that uses ADO connection to connect to another Excel workbook that serves as a database and retrieve & insert data via SQL queries. Please note I am not allowed to use Access in this case.
I have already figured out how to use SELECT, but there is one particular error with INSERT I can't resolve. That bothers me a lot, I've put a lot of work to it.
First the connection (I use JET for retrieving data and ACE for saving data as I was not able to get JET to work for that):
Public Sub InsertDataToSheet(SQLCmd As String)
Dim cnx As Object
Set cnx = CreateObject("ADODB.Connection")
cnx.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source='" & ThisWorkbook.Path & "\Database.xls'; Extended Properties=Excel 12.0;"
cnx.Execute SQLCmd
cnx.Close
End Sub
Then there is a subroutine linked to a Submit button that actually generates the Query as I need to save only filled out Textboxes and Combos to avoid Nulls:
Private Sub SaveRecord()
Dim SQL As String
SQL = "INSERT INTO [Report$A2:AM50000] ("
Dim i As Control
For Each i In Me.controls
If TypeName(i) = "TextBox" Or TypeName(i) = "ComboBox" Then
If i <> e Then SQL = SQL & i.Name & ","
End If
Next i
SQL = Mid(SQL, 1, Len(SQL) - 1) & ") VALUES(" ' Remove last space & comma
Dim j As Control
For Each j In Me.controls
If TypeName(j) = "TextBox" Or TypeName(j) = "ComboBox" Then
If j <> e Then
If j = "Unknown" Then MsgBox "Fire"
Select Case IsNumeric(j)
Case False
SQL = SQL & "'" & j & "'" ' Add single quotes around strings
Case True
SQL = SQL & j
End Select
SQL = SQL & ","
End If
End If
Next j
SQL = Mid(SQL, 1, Len(SQL) - 1) & ")" ' Remove last comma
' Connect
InsertDataToSheet (SQL)
End Sub
There are two particular textboxes in the form that work exactly the same. Normally, users enter numbers to them and everything saves fine (don't mind the '+' buttons):
Sometimes, however, users do not know the values but can't leave those empty. That's when they are supposed to tick the checkboxes to set the value(s) to 'Unknown':
Now there comes the funny part – for the Batch field, it saves fine. But when I set the Shipment ID to 'Unknown' (or any other string), it throws an error:
Note the fields are not Disabled, just Locked with some appearance changes. I was also unable to find any specific details about the error, but it seems there is some problem with the query:
(It says something like 'Incompatible data types in the expression'). The generated query is this:
Any ideas what goes wrong? I'd very much like to keep the functionality as it is know and solve the error rather than redesign it as it already took some effort and the fields can't stay empty.
Never used sql in xls workbooks, but I had this problem with SQL server already. There's nothing "wrong" with your query, the problem is that data type that's accepted on the field of the table you want to insert. Try to turn that field to use text values instead of numbers and it should work.

Attachmate receive host string and react with conditional response using VBA

Using Attachmate, I am trying to write a VBA script that reacts when a specific phrase occurs and automatically executes commands via inline commands. Essentially, when a phrase appears, an inputbox appears asking the user for a specific quantity and the VBA code takes that quantity, inserts it into the terminal and then jumps around different menus to create an internal label. However, my problem is that I don't know how to have the VBA code react to the different strings that may be returned by the host. Sometimes it says "enter to continue" and sometimes it says "select user". So what I want it to do is based on the statement it receives to do a certain action, but I don't know what the command is for capturing what the terminal is receiving from the host. I've tried "waitforstring" and "readline" but it is obvious I am not using them correctly. Below is the code I have built thus far, please be gentle as it is still very unfinished. I have commented out several parts of it in attempts to troubleshoot my problems:
'variable declarations
Dim count As Long 'var used to indicate how many times code should loop (how many labels should be print)
Dim drugname As String
Dim qtyinput As Long
Dim CR As String ' Chr(rcCR) = Chr(13) = Control-M
Dim LF As String ' Chr(rcLF) = Chr(10) = Control-J
Dim strcheck As String
'assign values to variables
count = 0
CR = Chr(Reflection2.ControlCodes.rcCR)
LF = Chr(Reflection2.ControlCodes.rcLF)
qtyinput = InputBox("Number of items being sent", Quantity)
drugname = .GetText(22, 15, 22, 46) ' StartRow:=22, StartColumn:=15,EndRow:=22, EndColumn:=46 'copies text from screen
' Press EditCopy (Copy the selection and put it on the Clipboard).
'.Copy rcSelection, rcAsPlainText -- not needed
.Transmit qtyinput & CR
.Transmit CR
'strcheck = .readline("00:00:01")
'MsgBox strcheck
'If .WaitForString("Press " & Chr(34) & "RETURN" & Chr(34) & " to continue, " & Chr(34) & "^" & Chr(34) & " to stop: ") Then .Transmit CR
'Select Case strcheck
' Case strcheck Like "to continue"
' .Transmit CR
'Case strcheck Like "*Select CLIENT*"
' .Transmit CR
'End Select
.Transmit "^MED" & CR
.Transmit "3" & CR
.Transmit "10" & CR
First of all, Attachmate is the company, and they have a few products for accessing Mainframe sessions from Windows including EXTRA! and Reflections, both of which share a common scripting language, which is nice and easy to use from within VBA.
However, EXTRA! tends to have fewer commands available to use than Reflections, which is the more expensive product, so you have to get a little creative with your VBA.
I think you are using EXTRA!, so the command you are looking for is "GetString"
I use VBA to interact with a mainframe session in EXTRA!, and I know that my mainframe command is successful when three stars appear on the screen in a certain position.
The mainframe command can take anywhere between 1 second and 5 minutes to complete, so I use "GetString" to poll the mainframe session every second, waiting for the three stars before I continue:
Do Until Sess0.Screen.GetString(14, 2, 3) = "***"
Application.Wait (Now + TimeValue("0:00:01"))
Loop
The syntax for "GetString" is: GetString(Row, Column, Length)
In my case the stars appear at row 14, column 2, and I know there will always be 3 of them, so I set my string length to 3.