VERY strange behavior on createobject("HTMLFILE")! - vba

I don't understand why I'm getting this strange behavior!
When creating and assigning the htmlfile object the function gives back a blank object ("nothing") and when I am running the code line by line it just runs automatically even when I don't press F8 to run the next line...
It gives no error whatsoever!
Any ideas as to what might be happening?
Line where the strange behavior starts: Set htmlObj = CreateObject("HTMLFILE")
Public Function XMLHTTP_Request(Method As String, URL As String, Optional PostData As String, Optional StrCookie As String) As HTMLDocument
Dim oXMLHTTP As Object, htmlObj as object
Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
oXMLHTTP.Open Method, URL, False
oXMLHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oXMLHTTP.setRequestHeader "Cookies", StrCookie
On Error GoTo ErrorHandler
oXMLHTTP.send (PostData)
On Error GoTo 0
While oXMLHTTP.ReadyState <> 4: DoEvents: Wend
While oXMLHTTP.Status <> 200: DoEvents: Wend
Set htmlObj = CreateObject("HTMLFILE")
htmlObj.body.innerHTML = oXMLHTTP.responseText
Set XMLHTTP_Request = htmlObj
End Function

Repeated calls to the function will cause multiple calls to the CreateObject function. The oXMLHTTP and htmlObj object vars could be made static or library references could be included and the variable declaration changed to Early Binding.
Early binding requires that the following non-default library references are added through the VBE's Tools ► References command.
Microsoft HTML Object Library
Microsoft Internet Controls
Microsoft XML 6.0 (your own version may vary slightly).
Module1 code sheet:
Option Explicit
Sub main()
Debug.Print Left(XMLHTTP_Request("http//example.com").body.innerText, 512)
End Sub
Public Function XMLHTTP_Request(URL As String, _
Optional Method As String = "POST", _
Optional PostData As String = "", _
Optional StrCookie As String = "") As HTMLDocument
Dim oXMLHTTP As New MSXML2.XMLHTTP60
Dim htmlObj As New HTMLDocument
oXMLHTTP.Open Method, URL, False
oXMLHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oXMLHTTP.setRequestHeader "Cookies", StrCookie
oXMLHTTP.send PostData
If oXMLHTTP.Status <> 200 Then Exit Function
htmlObj.body.innerHTML = oXMLHTTP.responseText
Set XMLHTTP_Request = htmlObj
End Function
Running the main() sub procedure will output the first 512 characters of the web page's text to the Immediate window ([Ctrl]+G).

Related

How to test whether WinHttpRequest works or if corporate security issue causes error

I found the following code on an excel forum:
Function URLExists(url As String) As Boolean
Dim Request As Object
Dim ff As Integer
Dim rc As Variant
On Error GoTo EndNow
Set Request = CreateObject("WinHttp.WinHttpRequest.5.1")
With Request
.Open "GET", url, False
.Send
rc = .StatusText
End With
Set Request = Nothing
If rc = "OK" Then URLExists = True
Exit Function
EndNow:
End Function
I see no reason why it would not work if I use a legitiamte URL. I have been testing it and keep on getting a FALSE returned. Opening the same URL in a browser works.
I suspect that this might have something to do with our coporate security settings. How can I test whether the code works or if it is a security issue?
The function goes to the error line on .Send

Excel VBA - extraordinary WinHttpRequest.Open error for only a few of url

Checking some URLs with
Function SiteStatus(ByVal URL As String, SiteStatusText As String) As Long
Dim oHttp As New WinHttp.WinHttpRequest
oHttp.Option(WinHttpRequestOption_EnableRedirects) = False
oHttp.Open "GET", URL, False
oHttp.Send
SiteStatus = oHttp.Status
SiteStatusText = oHttp.StatusText
End Function
generally works fine. Only a few URLs throw a VBA error -2147012744. The Server is giving an invalid or unknown response.
Some URLs in real work, I can open them with SHDocVw library, and some not, - that makes no difference.
for instance:
http: //s2.excoboard.com/Courthouse_Steps_Mavens/150601/1831324
or
http: //www.geld-und-leben.com/anleitung/
or
http: //globalnews.ca/news/3025046/justin-timberlakes-illegal-voting-booth-selfie-is-under-review/
I wanna check the status of these sites although.
How?
What's the point?
i know that this is old, but here is some VBA code that works.
some of the values for oHttp.Option came from http://www.808.dk/?code-simplewinhttprequest
Sub test()
' add reference to Microsoft WinHTTP Services
Dim URL As String
URL = "http://globalnews.ca/news/3025046/justin-timberlakes-illegal-voting-booth-selfie-is-under-review"
Dim oHttp As WinHttpRequest
Set oHttp = New WinHttpRequest
oHttp.Open "GET", URL, False
oHttp.Option(WinHttpRequestOption_UserAgentString) = "http_requester/0.1"
oHttp.Option(WinHttpRequestOption_SslErrorIgnoreFlags) = &H3300 ' ignore all err, 0: accept no err
oHttp.Option(WinHttpRequestOption_EnableRedirects) = True
oHttp.Option(WinHttpRequestOption_EnableHttpsToHttpRedirects) = True
oHttp.send
Do While True
DoEvents
If oHttp.Status Then Exit Do
Loop
Debug.Print oHttp.Status
End Sub

http response text fetching incomplete html

I have a code (given below) in excel vba that fetches web page source html. The code is working fine but the html that it fetches is incomplete. When the line webpageSource = oHttp.ResponseText is executed, the variable webpageSource contains "DOCTYPE html PUBLIC ....... etc etc till the end /html" and that is how it should be. Everything is correct till here. But the next line debug.print webpageSource prints only half the html from "(adsbygoogle = window.adsbygoogle || []).push({}); ...... etc etc till the end /html" Why is that so? I want to find some strings from the returned response text but since it is incomplete, I am unable to do so. Can someone shed some light on it?
Thanks
Sub source()
Dim oHttp As New WinHttp.WinHttpRequest
Dim sURL As String
Dim webpageSource As String
sURL = "http://www.somewebsite.com"
oHttp.Open "GET", sURL, False
oHttp.send
webpageSource = oHttp.ResponseText
debug.print webpageSource
End Sub
EDIT:
I also tried .WaitForResponse with no help :(
Debug.Print and/or the immediate window have limitations. Nowhere documented however they have.
So try writing the webpageSource to a file:
Sub source()
Dim oHttp As New WinHttp.WinHttpRequest
Dim sURL As String
Dim webpageSource As String
sURL = "http://www.google.com"
oHttp.Open "GET", sURL, False
oHttp.send
webpageSource = oHttp.ResponseText
Set FSO = CreateObject("Scripting.FileSystemObject")
Set oFile = FSO.CreateTextFile("webpageSource.txt")
oFile.Write webpageSource
oFile.Close
Shell "cmd /C start webpageSource.txt"
End Sub
Does the file contain all content?

XMLHTTP.send request brings back "Nothing"

I have a spreadsheet that has hundreds of links that point to a server (with authentication) that can be accessed via the web. I've been searching for a solution to a Link Checker in a spreadsheet that would tell me which links are broken and which are ok. By broken I mean that the website does not get called up at all.
There are various solutions I have found around the web, none of which work for me. I'm boggled by this...
One example that I've tried to use and figure out is re-posted below.
As I've stepped through the code, I have come to realize that the oHTTP.send request brings back "Nothing". It does so for all links in the spreadsheet, regardless of whether the link works, or not.
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
Any suggestions as to what might be wrong, or right, is highly appreciated!
A couple of possible causes..
Do you mean oHttp.Open "GET", strUrl, False instead of oHttp.Open "HEAD", strUrl, False ?
Perhaps MSXML2.XMLHTTP30 is not available? You can declare an instance of MSXML2.XMLHTTPX as either early bound or late bound which may impact which version you want to use vs what is available (example http://word.mvps.org/FAQs/InterDev/EarlyvsLateBinding.htm)
eg
Option Explicit
'Dim oHTTPEB As New XMLHTTP30 'For early binding enable reference Microsoft XML, v3.0
Dim oHTTPEB As New XMLHTTP60 'For early binding enable reference Microsoft XML, v6.0
Sub Test()
Dim chk1 As Boolean
Dim chk2 As Boolean
chk1 = CheckHyperlinkLB("http://stackoverflow.com/questions/11647297/xmlhttp-send-request-brings-back-nothing")
chk2 = CheckHyperlinkEB("http://stackoverflow.com/questions/11647297/xmlhttp-send-request-brings-back-nothing")
End Sub
Public Function CheckHyperlinkLB(ByVal strUrl As String) As Boolean
Dim oHTTPLB As Object
'late bound declaration of MSXML2.XMLHTTP30
Set oHTTPLB = CreateObject("Msxml2.XMLHTTP.3.0")
On Error GoTo ErrorHandler
oHTTPLB.Open "GET", strUrl, False
oHTTPLB.send
If Not oHTTPLB.Status = 200 Then CheckHyperlinkLB = False Else CheckHyperlinkLB = True
Set oHTTPLB = Nothing
Exit Function
ErrorHandler:
Set oHTTPLB = Nothing
CheckHyperlinkLB = False
End Function
Public Function CheckHyperlinkEB(ByVal strUrl As String) As Boolean
'early bound declaration of MSXML2.XMLHTTP60
On Error GoTo ErrorHandler
oHTTPEB.Open "GET", strUrl, False
oHTTPEB.send
If Not oHTTPEB.Status = 200 Then CheckHyperlinkEB = False Else CheckHyperlinkEB = True
Set oHTTPEB = Nothing
Exit Function
ErrorHandler:
Set oHTTPEB = Nothing
CheckHyperlinkEB = False
End Function
EDIT:
I tested the OP's link by opening in a browser which I've now discovered redirects to the login page instead so it's a different link I was testing. It's probably failing because the oHttp object has not been set to allow redirects. I know it's possible to set redirects for WinHttp.WinHttpRequest.5.1 using the code below. I would need to investigate if this also works for MSXML2.XMLHTTP30 though.
Option Explicit
Sub Test()
Dim chk1 As Boolean
chk1 = CheckHyperlink("http://portal.emilfrey.ch/portal/page/portal/toyota/30_after_sales/20_ersatzteile%20und%20zubeh%C3%B6r/10_zubeh%C3%B6r/10_produktbezogene%20informationen/10_aussen/10_felgen/10_asa-pr%C3%BCfberichte/iq/tab1357333/iq%20016660.pdf")
End Sub
Public Function CheckHyperlink(ByVal strUrl As String) As Boolean
Dim GetHeader As String
Const WinHttpRequestOption_EnableRedirects = 6
Dim oHttp As Object
Set oHttp = CreateObject("WinHttp.WinHttpRequest.5.1")
On Error GoTo ErrorHandler
oHttp.Option(WinHttpRequestOption_EnableRedirects) = True
oHttp.Open "HEAD", strUrl, False
oHttp.send
If Not oHttp.Status = 200 Then
CheckHyperlink = False
Else
GetHeader = oHttp.getAllResponseHeaders()
CheckHyperlink = True
End If
Exit Function
ErrorHandler:
CheckHyperlink = False
End Function
EDIT2:
MSXML2.XMLHTTP does allow redirects (although I believe MSXML2.ServerXMLHTTP doesn't). The redirects are allowed/disallowed depending upon whether the redirect is cross-domain, cross-port etc (see details here http://msdn.microsoft.com/en-us/library/ms537505(v=vs.85).aspx)
Since the redirect to the login page is cross-domain then IE zone policy is implemented. Open IE/Tools/Internet Options/Security/Custom Level and change 'Access data sources across domains' to ENABLED
The original OP's code will now redirect properly.

Find the current user language

How can I tell the current user language in a vba program?
I need this to show a form in an appropriate language.
My initial code (utilising this vbforum code) assumed that Windows and Excel share a common language - likely but not bulletproof.
updated
The revised code:
Returns the Locale ID (LCID).
Looks up the LCID from this msft link.
Parses the LCID using a regexp to get the language.
Sample output on my machine below
The code will let the user know if there are any errors in accessing the LCID website, or in parsing the country name.
Sub GetXlLang()
Dim lngCode As Long
lngCode = Application.LanguageSettings.LanguageID(msoLanguageIDUI)
MsgBox "Code is: " & lngCode & vbNewLine & GetTxt(lngCode)
End Sub
Function GetTxt(ByVal lngCode) As String
Dim objXmlHTTP As Object
Dim objRegex As Object
Dim objRegMC As Object
Dim strResponse As String
Dim strSite As String
Set objXmlHTTP = CreateObject("MSXML2.XMLHTTP")
strSite = "http://msdn.microsoft.com/en-us/goglobal/bb964664"
On Error GoTo ErrHandler
With objXmlHTTP
.Open "GET", strSite, False
.Send
If .Status = 200 Then strResponse = .ResponseText
End With
On Error GoTo 0
strResponse = Replace(strResponse, "</td><td>", vbNullString)
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Pattern = "><td>([a-zA-Z- ]+)[A-Fa-f0-9]{4}" & lngCode
If .Test(strResponse) Then
Set objRegMC = .Execute(strResponse)
GetTxt = objRegMC(0).submatches(0)
Else
GetTxt = "Value not found from " & strSite
End If
End With
Set objRegex = Nothing
Set objXmlHTTP = Nothing
Exit Function
ErrHandler:
If Not objXmlHTTP Is Nothing Then Set objXmlHTTP = Nothing
GetTxt = strSite & " unable to be accessed"
End Function
dim lang_code as long
lang_code = Application.LanguageSettings.LanguageID(msoLanguageIDUI)
This is another variation of the code posted by brettdj
Sub Test_GetLocale_UDF()
Dim lngCode As Long
lngCode = Application.LanguageSettings.LanguageID(msoLanguageIDUI)
MsgBox "Code Is: " & lngCode & vbNewLine & GetLocale(lngCode)
End Sub
Function GetLocale(ByVal lngCode) As String
Dim html As Object
Dim http As Object
Dim htmlTable As Object
Dim htmlRow As Object
Dim htmlCell As Object
Dim url As String
Set html = CreateObject("htmlfile")
Set http = CreateObject("MSXML2.XMLHTTP")
url = "https://www.science.co.il/language/Locale-codes.php"
On Error GoTo ErrHandler
With http
.Open "GET", url, False
.send
If .Status = 200 Then html.body.innerHTML = .responseText
End With
On Error GoTo 0
Set htmlTable = html.getElementsByTagName("table")(0)
For Each htmlRow In htmlTable.getElementsByTagName("tr")
For Each htmlCell In htmlRow.Children
If htmlCell.innerText = CStr(lngCode) Then
GetLocale = htmlRow.getElementsByTagName("td")(0).innerText
Exit For
End If
Next htmlCell
Next htmlRow
If GetLocale = "" Then GetLocale = "Value Not Found From " & url
Exit Function
ErrHandler:
If Not http Is Nothing Then Set http = Nothing
GetLocale = url & " Unable To Be Accessed"
End Function
Select Case Application.International(xlApplicationInternational.xlCountryCode)
Case 1: Call MsgBox("English")
Case 33: Call MsgBox("French")
Case 49: Call MsgBox("German")
Case 81: Call MsgBox("Japanese")
End Select
Straight out of here: https://bettersolutions.com/vba/macros/region-language.htm
Relevant Documentation: https://learn.microsoft.com/en-us/office/vba/api/excel.xlapplicationinternational
VBA Application.LanguageSettings.LanguageID(msoLanguageIDUI) gets only Microsoft Office Access or Microsoft Excel User interface Language. But does not reflect the Windows System display language used for Windows Display, every thing as MsgBox() buttons etc.
If user changes his Windows Display language via Windows Control Panel, this Application level setting will not change. In which case, we can use this Kernel dll function to get the new LCID (Microsoft Language Code IDentifier, 1036=French, 1033=English, ...), with this code in a VBA Module:
Private Declare Function GetUserDefaultUILanguage Lib "kernel32.dll" () As Long
Public Function winGetUserDefaultUILanguage()
winGetUserDefaultUILanguage = GetUserDefaultUILanguage()
End Function
Then you can call the public function winGetUserDefaultUILanguage() every where in your VBA code to get Windows LCID.
The kernel dll function GetUserDefaultUILanguage() will reflect the changement via Windows Display Language ID.
For example, as I've French Windows display language, LCID=1036, my Office is also in French (LCID=1036),
VBA Debugger Console:
Now we switch to English Windows display language via Control Panel (LCID=1033 for English), but my Office language ID remains unchanged (LCID=1036):
VBA Debugger Console:
From LCID, you can further get Language Tag, Language Name from Microsoft API documents here or here.