Tag Archives: Visual Basic

Call a WebService from VBScript

While I was writing some code on VBScript to avoid manual tasks that we currently do with a bunch of files, I needed to automatically upload some information extracted from all these files to a SQL database. One way to do it is using a Web Service that receives the data and store it into the database.

Our Web Service is able to receive the following protocols: SOAP 1.1, SOAP 1.2 and HTTP POST. For simplicity, we are going to use HTTP POST, which receive the parameters in the query string format (param1=value1&param2=value2&…). In the other protocols (SOAP) we would need to send the parameters in a XML way (which is more powerful but a little more extensive to implement).

The expected HTTP request will be:

POST /WebService.asmx/WebMethod HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: length

param=string

And the response (in XML format):

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">string</string>

So, to call the Web Service directly from the VBScript, we can use the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
'The object that will make the call to the WS
Set oXMLHTTP = CreateObject("Microsoft.XMLHTTP")
'The object that will receive the answer from the WS
Set oXMLDoc = CreateObject("Microsoft.XMLDOM")
 
strParam = "string to pass"
 
'Tell the name of the subroutine that will handle the response
oXMLHTTP.onreadystatechange = getRef("HandleStateChange")
'Initializes the request (the last parameter, False in this case, tells if the call is asynchronous or not
oXMLHTTP.open "POST", "http://localhost/WebService.asmx/WebMethod", False
'This is the content type that is expected by the WS using the HTTP POST protocol
oXMLHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
 
'Now we send the request to the WS
oXMLHTTP.send "parameter=" & strParam
 
Sub HandleStateChange()
	Dim szResponse
	'When the call has been completed (ready state 4)
	If oXMLHTTP.readyState = 4 Then
		szResponse = oXMLHTTP.responseText
		oXMLDoc.loadXML szResponse
		'If the WS response is not in XML format, there is a problem
		If oXMLDoc.parseError.errorCode <> 0 Then
			WScript.Echo "ERROR:"
			WScript.Echo oXMLHTTP.responseText
			WScript.Echo oXMLDoc.parseError.reason
		Else
			WScript.Echo "Result: " & oXMLDoc.getElementsByTagName("string")(0).childNodes(0).Text
		End If
	End If
End Sub

The ready state tells us about the connection with the Web Service:

  • 0: Uninitialized – open() has not been called yet.
  • 1: Loading – send() has not been called yet.
  • 2: Loaded – send() has been called, headers and status are available.
  • 3: Interactive – Downloading, responseText holds the partial data.
  • 4: Completed – Finished with all operations.

Subrutinas para VBA

Por más que no sea un gran fan de Microsoft, debo admitir que el Office es un buen producto. A mi me gusta especialmente el Excel por la cantidad de cosas que se pueden hacer con él. Si además, lo utilizamos en conjunto con VBA (el pequeño entorno de desarrollo en Visual Basic que está metido dentro del Office), el número de posibilidades se incrementa exponencialmente. Es cierto que el VB está muy, muy lejos de ser el mejor lenguaje de programación, pero en este caso cumple su cometido (aunque muchas veces extrañe las ventajas de lenguajes más elaborados como C#).

Bueno, regresando al tema de este post, quería colocar acá algunas subrutinas que utilizo cuando programo en VBA. Creo que pueden ser útiles a más de uno, además que me sirven a mi cuando comienzo un nuevo proyecto.

' Adds a new worksheet to the current workbook.
' Name of the sheet should be pass as a parameter.
' If a sheet with the same name already exists, it is deleted prior creation.
Sub AddSheet(sheetName As String)
    RemoveSheet (sheetName)
    ' Added as last sheet
    Sheets.Add After:=Sheets(Sheets.count)
    Sheets(Sheets.count).name = sheetName
End Sub
 
' Deletes a worksheet from the current workbook.
Sub RemoveSheet(sheetName As String)
    Dim alerts As Boolean
    If SheetExists(sheetName) Then
        alerts = Application.DisplayAlerts
        ' Avoid alert on delete
        Application.DisplayAlerts = False
        Sheets(sheetName).Delete
        Application.DisplayAlerts = alerts
    End If
End Sub
 
' Returns TRUE if there is a worksheet with the given name on the active workbook.
Function SheetExists(sheetName As String) As Boolean
    SheetExists = False
    On Error GoTo NoSuchSheet
    If Len(Sheets(sheetName).name) &gt; 0 Then
        SheetExists = True
        Exit Function
    End If
NoSuchSheet:
End Function

UPDATE: He encontrado que el cambio de nombre de la hoja en AddSheet puede fallar si existen hojas ocultas en el libro. Así que estoy buscando una solución, apenas la tenga la cuelgo.