function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
David ThomasDavid Thomas 

Using PocketSOAP to call the SOAP API from VBScript/VB6

I'm after a recent working example (code) that I can prototype in VBScript and then pass onto my client, who needs to make a targeted change to a legacy VB6 app to make a real-time query against a Contact record in Salesforce.  The query is currently against a SQL DB that is not part of the legacy app, but will be migrated to salesforce.com.

The code I'm using (below), fails on when trying to parse the response (e.parse t)
--> Error during parsing, no element found at line 1
--> Code: 80044240, PocketSOAP.Envelope.11:

This article (https://developer.salesforce.com/forums/ForumsMain?id=906F00000008rMBIAY) from 2004 with replies from the PocketSOAP creator @Superfell is useful, but doesn't quite have a full example.

' PocketSOAP calling SOAP API / Partner WSDL

dim e
set e = CreateObject("PocketSOAP.Envelope.2")
' CLSID: {E2E0FB24-E58F-458f-84E0-6E09D2D51511}

e.EncodingStyle = ""
e.SetMethod "login", "urn:enterprise.soap.sforce.com"
'e.URI = "urn:enterprise.soap.sforce.com"

e.Parameters.Create "username", "sfdcuser@org.com", "urn:login"
e.Parameters.Create "password", "pwd+token", "urn:login"

' CLSID: {C7899023-E487-4268-AE2A-4EC50136DAB3}
'set mgr = CreateObject("pocketSOAP.Attachments")
'mgr.Format = formatMime

' CLSID: {D76BA06F-ABF3-4c1f-BDC9-1848D4E3CF2B}
dim t
set t = CreateObject("PocketSOAP.HTTPTransport.2")
t.SOAPAction = ""

t.Send "https://test.salesforce.com/services/Soap/u/29.0/", e.serialize

wscript.echo e.serialize

e.parse t ' <--- fails here with 'Error during parsing, no element found at line 1
' Code: 80044240, PocketSOAP.Envelope.11

wscript.echo "debug = " & e.parameters.item(0).Value

Best Answer chosen by David Thomas
SuperfellSuperfell
Sounds like you might need to configure it to use a proxy as its not getting a valid soap response. (if you do there's  a SetProxy call available on the transport object) Here's a complete example that calls login and then query, run it with cscript sfdc.vbs username password

' PocketSOAP calling SOAP API / Enterprise WSDL

dim e, t, h, serverUrl, sessionId, result, records, ns
ns = "urn:enterprise.soap.sforce.com"

' create the login envelope
set e = CreateObject("PocketSOAP.Envelope.2")
e.EncodingStyle = ""
e.SetMethod "login", ns
e.Parameters.Create "username", wscript.Arguments.Item(0), ns
e.Parameters.Create "password", wscript.arguments.Item(1), ns

' send it
set t = CreateObject("PocketSOAP.HTTPTransport.2")
t.SOAPAction = ""
t.option("compression.accept") = false
' note that you have to use the Soap/c URL here as we're using the enterprise API namesace in the messages
t.Send "https://login.salesforce.com/services/Soap/c/29.0", e

' extract serverUrl & sessionId from the response
e.parse t
set result = e.parameters.Item(0)
serverUrl = result.Nodes.ItemByName("serverUrl", ns).Value
sessionId = result.Nodes.ItemByName("sessionId", ns).Value

' create the query envleope
set e = CreateObject("PocketSOAP.Envelope.2")
e.encodingStyle = ""
' create the sessionId header
set h = e.Headers.Create("SessionHeader", "", ns)
h.Nodes.Create "sessionId", sessionId, ns

e.setMethod  "query", ns
e.parameters.create "query", "select Id, name from account order by systemModStamp desc limit 5", ns

' send the query request and parse the results
t.send serverUrl, e
e.parse t
set result = e.Parameters.Item(0)
set records = result.Nodes.ItemByName("records", ns)

for each qr in result.Nodes
if (qr.Name = "records") then
  wscript.echo "record"
  for each f in qr.Nodes
   wscript.echo "    " & f.Name & ":" & f.Value
  next
end if
next

 
When i run this i get

Microsoft (R) Windows Script Host Version 5.7
Copyright (C) Microsoft Corporation. All rights reserved.

record
    Id:0013000000iJR75AAG
    Name:Dropbox
record
    Id:00130000013DqD0AAK
    Name:Bobby
record
    Id:0013000001FBYUMAA5
    Name:Medlife
record
    Id:0013000001FAisaAAD
    Name:Foo
record
    Id:0013000001FAisbAAD
    Name:Foo2

All Answers

SuperfellSuperfell
Sounds like you might need to configure it to use a proxy as its not getting a valid soap response. (if you do there's  a SetProxy call available on the transport object) Here's a complete example that calls login and then query, run it with cscript sfdc.vbs username password

' PocketSOAP calling SOAP API / Enterprise WSDL

dim e, t, h, serverUrl, sessionId, result, records, ns
ns = "urn:enterprise.soap.sforce.com"

' create the login envelope
set e = CreateObject("PocketSOAP.Envelope.2")
e.EncodingStyle = ""
e.SetMethod "login", ns
e.Parameters.Create "username", wscript.Arguments.Item(0), ns
e.Parameters.Create "password", wscript.arguments.Item(1), ns

' send it
set t = CreateObject("PocketSOAP.HTTPTransport.2")
t.SOAPAction = ""
t.option("compression.accept") = false
' note that you have to use the Soap/c URL here as we're using the enterprise API namesace in the messages
t.Send "https://login.salesforce.com/services/Soap/c/29.0", e

' extract serverUrl & sessionId from the response
e.parse t
set result = e.parameters.Item(0)
serverUrl = result.Nodes.ItemByName("serverUrl", ns).Value
sessionId = result.Nodes.ItemByName("sessionId", ns).Value

' create the query envleope
set e = CreateObject("PocketSOAP.Envelope.2")
e.encodingStyle = ""
' create the sessionId header
set h = e.Headers.Create("SessionHeader", "", ns)
h.Nodes.Create "sessionId", sessionId, ns

e.setMethod  "query", ns
e.parameters.create "query", "select Id, name from account order by systemModStamp desc limit 5", ns

' send the query request and parse the results
t.send serverUrl, e
e.parse t
set result = e.Parameters.Item(0)
set records = result.Nodes.ItemByName("records", ns)

for each qr in result.Nodes
if (qr.Name = "records") then
  wscript.echo "record"
  for each f in qr.Nodes
   wscript.echo "    " & f.Name & ":" & f.Value
  next
end if
next

 
When i run this i get

Microsoft (R) Windows Script Host Version 5.7
Copyright (C) Microsoft Corporation. All rights reserved.

record
    Id:0013000000iJR75AAG
    Name:Dropbox
record
    Id:00130000013DqD0AAK
    Name:Bobby
record
    Id:0013000001FBYUMAA5
    Name:Medlife
record
    Id:0013000001FAisaAAD
    Name:Foo
record
    Id:0013000001FAisbAAD
    Name:Foo2
This was selected as the best answer
David ThomasDavid Thomas
Thanks for the quick response and full example!  It now works a treat.

One followup question ... do you recommend I use the Enterprise WSDL, or is the Partner WSDL also fine?  Any gotchas I should be aware of?
(I did get the Partner WSDL working by changing the endpoint and namespace, and got a slightly different return result format.)

A good tip for readers on Windows 7 is to make sure you use the 32-bit version of cscript, i.e. c:\windows\syswow64\cscript.exe, to avoid automation errors.

Initially the script failed with the same Automation error, but I'd been running 64-bit cscript and hacking the registry to configure thunking (http://www.gfi.com/blog/32bit-object-64bit-environment/).  As I only did the CoClasses in the CreateObject statements, I suspect I may have missed some dependent classes that were causing the failure.

Now that I have the VBS version working (no corporate firewall), I'll move onto the VB6 case from behind the firewall and introduce the proxy.

Nice coffee pic btw -- reminds me of my favourite roaster Campos here in Sydney.  Let's do coffee if you're in town any time, my shout.

JeyaJeya
Its working like a charm in production but fails to connect the pre-production with the below exception.

{urn:fault.partner.soap.sforce.com}UNSUPPORTED_CLIENT : UNSUPPORTED_CLIENT: TLS 1.0 has been disabled in this organization. Please use TLS 1.1 or higher when connecting to Salesforce using https.

Do we need to update the component? Highly appreciate your help.