WinHttp, ASP, VBScript, JScript...



Windows Scripting

This is a collection of bits of information and tutorials that I wrote when doing extensive work with scripting on Windows XP and thereon. These are still relevant if you're using ActiveX objects or running scripts with cscript or wscript. The particular dialect of JavaScript I focus on is JScript.


WinHttp.WinHttpRequest.5.1

I got tired of waiting for MSDN as a reference to using the WinHttp ActiveXObject, so I'm transcribing things here. Visit MSDN's WinHttpRequest Object Reference for the original content.

WinHttpRequest Methods

WinHttpRequest Properties

WinHttpRequest Events

WinHttpRequest . GetResponseHeader

The GetResponseHeader method gets the HTTP response headers.

Return Value = GetResponseHeader( *bstrHeader )

* = Required

Invoke this method only after the Send method has been called.

The following code example shows how to open an HTTP connection, send an HTTP request, and get the date header from the response.

// Instantiate a WinHttpRequest object.
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");

// Initialize an HTTP request.
WinHttpReq.Open("GET", "http://example.com", false);

// Send the HTTP request.
WinHttpReq.Send();

// Display the date header.
WScript.Echo( WinHttpReq.GetResponseHeader("Date"));

WinHttpRequest . Open

The Open method opens an HTTP connection to an HTTP resource.

Open( *bstrMethod, *bstrUrl, varAsync = false )

* = Required.

This method opens a connection to the resource identified in bstrUrl using the HTTP verb given in bstrMethod.

The following code example shows how to open an HTTP connection, send an HTTP request, and read the response text.

// Instantiate a WinHttpRequest object.
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");

// Initialize an HTTP request.
WinHttpReq.Open("GET", "http://example.com", false);

// Send the HTTP request.
WinHttpReq.Send();

// Display the response text.
WScript.Echo( WinHttpReq.ResponseText);

WinHttpRequest . Send

The Send method sends an HTTP request to an HTTP server.

Send( varBody )

The request to be sent was defined in a prior call to the Open method. The calling application can provide data to be sent to the server through the varBody parameter. If the HTTP verb of the object's Open is "GET", this method sends the request without varBody, even if it is provided by the calling application.

The following example shows how to open an HTTP connection, send an HTTP request, and read the response text.

// Instantiate a WinHttpRequest object.
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");

// Initialize an HTTP request.
WinHttpReq.Open("GET", "http://example.com", false);

// Send the HTTP request.
WinHttpReq.Send();

// Display the response text.
WScript.Echo( WinHttpReq.ResponseText);

The following example shows how to post data to an HTTP server.

// Instantiate a WinHttpRequest object.
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");

// Initialize an HTTP request.
WinHttpReq.Open("PUT", "http://postserver/newdoc.htm", false);

// Post data to the HTTP server.
WinHttpReq.Send("Post data");

WinHttpRequest . SetTimeouts

The SetTimeouts method specifies the individual time-out components of a send/receive operation, in milliseconds.

SetTimeouts( ResolveTimeout, ConnectTimeout, SendTimeout, ReceiveTimeout )

All parameters are required. A value of 0 or -1 sets a time-out to wait infinitely. A value greater than 0 sets the time-out value in milliseconds. For example, 30,000 would set the time-out to 30 seconds. All negative values other than -1 cause this method to fail.

Time-out values are applied at the Winsock layer.

The following example shows how to set all WinHTTP time-outs to 30 seconds, open an HTTP connection, and send an HTTP request.

// Instantiate a WinHttpRequest object.
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");

// Set time-outs. If time-outs are set, they must
// be set before open.
WinHttpReq.SetTimeouts(30000, 30000, 30000, 30000);

// Initialize an HTTP request.
WinHttpReq.Open("GET", "http://example.com", false);

// Send the HTTP request.
WinHttpReq.Send();

WinHttpRequest . WaitForResponse

The WaitForResponse method waits for an asynchronous Send method to complete, with optional time-out value, in seconds.

Return Value = WaitForResponse( Timeout = -1)

This method suspends execution while waiting for a response to an asynchronous request. This method should be called after a Send. Calling applications can specify an optional Timeout value, in seconds. If this method times out, the request is not aborted. This way, the calling application can continue to wait for the request, if desired, in a subsequent call to this method.

Calling this property after a synchronous Send method returns immediately and has no effect.

This example shows how to open an asynchronous HTTP connection, send an HTTP request, wait for a response, and read the response text.

// Instantiate a WinHttpRequest object.
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");

// Initialize an HTTP request.
WinHttpReq.Open("GET", "http://example.com", true);

// Send the HTTP request.
WinHttpReq.Send();

// Wait for the response.
WinHttpReq.WaitForResponse();

// Display the response text.
WScript.Echo( WinHttpReq.ResponseText);

JavaScript: Constructor Return Value

What happens when a constructor returns a value?

A constructor in JavaScript is any function which handles being called using the new operator. What happens is a blank Object is instantiated and accessible to said method via a this reference. Two things a constructor will typically do is assign a prototype and add instance-based members. However, you constructors can return values to manipulate what object the caller receives using the return value!

If a constructor function returns nothing, null, or any atomic / non-object value then said value is ignored and the newly created object reference is given back to the caller. For example, a return value of 0 (zero) from a constructor function will be ignored.

function Deebee() { return 0; }
var db = new Deebee();
if (!db)
  throw Error("JS constructor returned non-object!");

The second piece of magic eluded to above is the ability for a constructor to return a specific, possibly pre-existing object, rather than a reference to a new instance. This would allow you to manage the number of actual instances yourself if needed; possibly for reasons of limited resources or whatnot.

var g_deebee = new Deebee();
function Deebee() { return g_deebee; }
var db1 = new Deebee();
var db2 = new Deebee();
if (db1 != db2)
  throw Error("JS constructor returned wrong object!");

Unfortunately there are no inherent destructors in JavaScript, no way to be called when an object is out of scope and about to be garbage collected. Typically the way to get around this is to write more procedurally when working with scripts controling finite resources, e.g. explicitely call some close/destroy/quit/end/etc. function after you're finished. This is another reason you might opt to share object references so your script can keep track and not exceed any limits which would cause exceptions.

Finally, remember that instead of using a global variable, you can store references on the function object itself. I recommend it to better compartmentalize the logic under a single entry in the global namespace, and so it's not actually executed until needed.

function Deebee()
{
  if (undefined == Deebee.o)
    Deebee.o = this;
  return Deebee.o;
}

Check out the full-script example: [ex-constructor-return.js]. You can run this in Windows from a command prompt by typing:

cscript.exe ex-constructor-return.js

Or try it in your web browser by putting it in a HTML document:

<script language="JavaScript" src="ex-constructor-return.js" >

Constructor magic!


JavaScript: Difference between null and undefined

Here is one of the most confusing aspects of an otherwise very simple language: two, seemingly redundant ways to represent "no value here buddy, walk it off" (or a fact simile). One is null and the other is undefined. Here's what ECMA3 has to say about these:

The undefined value is a primitive value used when a variable has not been assigned a value. The null value is a primitive value that represents the null, empty, or non-existent reference.

It's been a while since I read through the entire thing, but I don't recall it ever getting more specific than that, pretty vague if you ask me. So what is the difference between null and undefined in JavaScript? This is rather difficult to explain for me, so bear with, and these differences seem so subtle as to be almost inconsequential.

When you declare a variable through var and do not give it a value, it will have the value undefined. By itself, if you try to WScript.Echo() or alert() this value, you won't see anything. However, if you append a blank string to it then suddenly it'll appear:

var s;
WScript.Echo(s);
WScript.Echo("" + s);

You can declare a variable, set it to null, and the behavior is identical except that you'll see "null" printed out versus "undefined". This is a small difference indeed.

You can even compare a variable that is undefined to null or vice versa, and the condition will be true:

undefined == null
null == undefined

They are, however, considered to be two different types. While undefined is a type all to itself, null is considered to be a special object value. You can see this by using typeof() which returns a string representing the general type of a variable:

var a;
WScript.Echo(typeof(a));
var b = null;
WScript.Echo(typeof(b));

Running the above script will result in the following output:

undefined
object

Regardless of their being different types, they will still act the same if you try to access a member of either one, e.g. that is to say they will throw an exception. With WSH you will see the dreaded "'varname' is null or not an object" and that's if you're lucky (but that's a topic for another article).

You can explicitly set a variable to be undefined, but I highly advise against it. I recommend only setting variables to null and leave undefined the value for things you forgot to set. At the same time, I really encourage you to always set every variable. JavaScript has a scope chain different than that of C-style languages, easily confusing even veteran programmers, and setting variables to null is the best way to prevent bugs based on it.

Another instance where you will see undefined pop up is when using the delete operator. Those of us from a C-world might incorrectly interpret this as destroying an object, but it is not so. What this operation does is remove a subscript from an Array or a member from an Object. For Arrays it does not effect the length, but rather that subscript is now considered undefined.

var a = [ 'a', 'b', 'c' ];
delete a[1];
for (var i = 0; i < a.length; i++)
WScript.Echo((i+".) "+a[i]);

The result of the above script is:

0.) a
1.) undefined
2.) c

You will also get undefined returned when reading a subscript or member that never existed.

Maybe you are seeing the theme in the differences?

The difference between null and undefined is: JavaScript will never set anything to null, that's usually what we do. While we can set variables to undefined, we prefer null because it's not something that is ever done for us. When you're debugging this means that anything set to null is of your own doing and not JavaScript. Beyond that, these two special values are nearly equivalent.


JavaScript: Call Function based on String

Wondering about calling a function from a string in JavaScript (including ActionScript in Flash/Flex)? Lest you forget, the language contains very few operators/keywords and is yet dynamic to the core. Practically everything is an object, even functions, and you can grab almost any property of said objects using the square-bracket syntax:

var s = "hello";
var s2 = this['s'];

Thus to call a function based on a string, you merely need to pull it off of an object and put the name in square brackets. If you're at the global level, or want a global function, you can use what I call the global context or global this reference:

function foo() { }

this["foo"]();

Obviously you could use a variable in place of the string literal:

var funcname = "foo";
this[funcname]();

If you're calling a function on an object instance, even an ActiveX/COM object in JScript, just put that object name followed by the function name in subscript form:

// in WSH/JScript ...
WScript["Echo"]("Hello World!");

// in web browser ...
document["write"]("Hello World!");

Since you're just trying to resolve down to a function-type, you can chain these together:

this["document"]["write"]("Bit contrived...");

When trying to call a global function from inside object methods you'll find the this reference is for that current instance of the object and not the global namespace. In that case you'll need to have either cached the global context or you can get it by calling any function without object context and have it return this, like so:

var gthis = (function(){return this;})();

In the above code I'm creating an anonymous function and executing it at the same time.


ASP: Mixed Include Techniques

Classic ASP provides two ways for linking to other code files: the pound-include comment (<--#include file="filename.asp" -->) and a server-side script tag (<--script runat="server" src="filename.js" language="JScript"></script>). In general I prefer to use the latter, because I can write portable ECMAScript and worry less about the syntax highlighting issues that come with combining languages (HTML/JScript/VBScript) in the same file. I'd like to point out here at the beginning that ASP by itself is a platform and not a language, it actually stands for "Active Server Page(s)". Being a JavaScript buff myself, I tend to use Microsoft's implementation of that language which is technically labeled JScript. Still when people ask if you write ASP code generally they mean VBScript, which is a fine language but not one I'm overly familiar with or will be using here -- sorry.

The biggest difference between these two methods of code inclusion is the first imports a new Active Serve Page and the second imports functions (or classes) written in a specific Active Script language. Additionally the logic in a script tag is always run after everything in straight-up ASP files. This has two side effects:

  1. Global variables declared in an external script file are not available to the code in an ASP.
  2. Global code in an external script is run after everything in the ASP file (unless Response.End() is used) and can therefore cause exceptions which screw something up which already succeeded.

I mainly advise that you explicitely call Response.End() with the ASP to ensure other weird global code won't execute and cause problems. In order to have your scripts play nice, you'll also have to avoid relying on global variables because they simply won't be initialized, though it is possible to set global variables in an external script through a function that is called from within the ASP.

The global this context reference is different when it is created from code in the ASP versus when external script code is run. I can't explain exactly how, but basically you can't enumerate it like a normal JavaScript object because it simply isn't. Thus the following would cause an exception ...

test.asp

<%@Language=JScript%>

<script language="JScript" src="module.js" runat="server"></script>

Test();

module.js

function Test()
{
  for (var nm in this)
  {
    // ...
  }
}

While you can't enumerate the this object, you can still access it for direct reads or explicit assignments. Whatever you assign to this will from then-on be a globally accessible variable in both the ASP code and external scripts.

Okay I said I wasn't going to talk about VBScript, but here's a doozey of an issue to keep in mind. External JScript files are executed before your ASP code if the language is set to VBScript. It must have something to do with the way ASP handles language switching, but I couldn't tell you for certain.


ASP: VBScript to JavaScript

This was a conversation I had with a friend via instant messaging that I thought others might find useful. It's about his transition from using VBScript in ASP (Active Server Pages) to JavaScript (or rather, Microsoft's version which is JScript).

Leon: this isnt working...

><%@ LANGUAGE="JScript" %>
<% option explicit %>
<% var test='test!'; %>
<% response.write test %>

am i retarded?

Leon: its ok to say yes

Neil: Yes, there is no such thing as "option explicit" in JavaScript

Neil: Also, you need parenthesis around parameters. Also, I wouldn't put those in separate blocks, just use one ....

<%@Language=JScript%><%
var test = "test!";
Response.Write(test);
%>

Leon: thank you!

Leon: OMG, the chains or opression have been cast aside!

Leon: what about set obj = server.createobject("object") ?

Neil: var obj = Server.CreateObject("object");

Neil: There is no SET

Neil: Remember it's JavaScript, same function calls can be made (for the most part), but the language syntax is definitely different

Leon: right, i wasnt sure about set and thats not the kind of thing i can search a pdf for

Leon: what about "nothing" professor is that still a valid way to release an asp object?

Neil: Nothing is a VB keyword, not a JS keyword

Leon: im trying to find examples but everyone just says you can use js but noone actually showing any examples

Neil: I know, maybe I should start writing some

var obj = Server.CreateObject("blahblah");
obj = null;

Leon: sweet

Leon: and single quotes are safe?

Neil: JS makes no distinction between single or double as long as you close with the same type you opened with...

'okay'
"okay"
'not okay"
"not okay'

Neil: It's useful when you know what kind of quotes might be IN your string, because you can embed them easier ...

'some "double" quotes'
"some 'single' quotes"

Leon: i like the first

Neil: I noticed a lot of web pages use single quotes in JS, almost as if they don't realize you can use double quotes.

Leon: coming from a vbs bg its crippled my thinking.. its like not a real string unless its in the ""... i mean.. you never know maybe it isnt a string.. maybe its some string out of access that will never evaluate.. 

Leon: like why is this an unterminated string constant?

objFileSys = objFSO.getFile(envSys+"\"+f);

Neil: Backslashes are used to escape characters. Remember how I told you \r\n is CRLF? So "line1\r\nline2". So if JS sees a backslash, it sees an escape character. In your case a backslash followed by a quote ( \" ) means simply a quote character. This allows you to put quotes inside quotes:

"outside \"inside quotes\" outside"

Leon: oh yeah

Leon: so i need an /\

Neil: Then to put an actual backslash CHARACTER into a string, you need to escape it as well. Do that by using TWO backslashes:

"c:\\windows"

Leon: cool

Neil: If you ever learn C/C++/Java/C#/PHP, they have the same escaping system.

Leon: is there a way you can define a var that can contain multi level values like

var.value1 = "1"
var.value2 = "2"

Neil: I don't understand what you're asking, show me what you'd do in VBS.

Leon: i dont know what im talking about honsetly i just know in lua i can make a var like this

test.letter1 = "A"
test.letter2 = "B"
test.letter3 = "C"

and then use the value like test=test.letter1

Leon: i was wondering if there was anything like that

Neil: So you mean a variable is constrained to a specific set of values (e.g. an enumeration)? No, that is not supported

Leon: not really usefule i was just wondering

Neil: You would either just use the value you wanted (test = "C") or create a variable holding the value(s) you wanted (test = test_letter1)

Leon: what about a hash or dictionary equiv, you know a tutorial for that?

Leon: wait, i think i found one

Neil: Hash/dictionary/associative arrays are native to JavaScript. An object you create can be used or accessed like one.

Neil: An example will help here though ...

var dic = new Object;
dic["apple"] = "A sweet fruit or an over-hyped company";
dic["pear"] = "A sweet fruit or how you look with shorts on";

var key = "apple";
Response.Write(dic[key]);

Neil: You could even access these directly:

Response.Write(dic.apple);
Response.Write(dic.pear);,

Neil: To enumerate an object (or lo, a dictionary as it would've been known to you):

for (key in dic)
{
  Response.Write(key + ": " + dic[key]);
}

Leon: so what your telling me is the only thing thats useful in vbs, the dictionary is functionality found in any js object?

Neil: Yes, it's one of its strengths. It makes it so you can do all kinds of crazy, dynamic shit

Leon: godamnit, why the fuck is vbs even sugested

Neil: People are familiar with it, and it's not as scary looking with all the braces and semi-colons

Leon: yeah.. the braces are intimidating at first, i dont know why but they serve to confuse

Neil: Python and Ruby are a lot like JS without the braces (or one might say, it's the other way around).

Neil: The one dominating reason why I use JS over those other two is 1. you can use it right-away on ANY fresh Windows install (due to WSH), and 2. EVERYONE's browser supports JS these days

Leon: now why is it then when i call server.mappath it tells me that 'server' is not defined.. oh does it have to be 'Server'?

Leon: ha

Neil: Yes, and case sensitivity is a big weak point (in my opinion)

Neil: But, it's too late to change it now. Too many scripts might explode into fiery kiddie bits if we make the language insensitive to case

Leon: you dont like being able to have a VAR thats one thing and var thats another?

Neil: I do only when it serves to irritate people who will inherit my code

Leon: hahahaha

Leon: good point

Leon: couldnt you do some kind of lcase execute call thing to ensure everything was allways lowercase

Neil: Hmm, I'm not sure what you mean. A lot of objects have a specific case, like "Server" the 'S' has to be upper-case

Leon: well thats why i click the mouse for a living rather then press the keys

Leon: hmmm i cant replace on a server var.. do i have to convert it to a string youd think it would already be one..

Neil: Ok, so you mean Request.QueryString() or something like that? What are you trying to do now? You can show me VBS and I'll help you write the JS

Leon: var = Request.ServerVariables("APPL_PHYSICAL_PATH").replace(/chars/, "newcars");

Leon: Object doesn't support this property or method

Neil: This is one of those things that is fortunately hidden from you in VB, because the ASP objects were tailored for that language. In JavaScript you can do one of two things:

var s = Request.ServerVariables("name").Item(1).replace(....);

or

var s = (""+Request.ServerVariables("name")).replace(....);

Leon: oh i get you, is there a parseString function or is that wrong too

Neil: What do you want to parse a string to? An int?

var i = parseInt("54");

if (isNaN ( i ) )
{
  // parsing failed
}

Neil: NaN == Not a Number

Leon: and how do you make a replace global?

Leon: /g?

Neil: Ah, another annoyance, yes. You need to use a regular expresion, correct

var s = "hello world world".replace(/world/g, "planet");

Leon: ok i got it, i shouldnt have asked that when i could have googled it so easy


Save Binary File to Disk in JavaScript

Question:

...I am consuming an XML web service using javascript..

One of the elements is a base64 encoded byte array... so it is a binary array of a document from my webserver... I REALLY need to know how I can from the client write this file to disk on my client using javascript... I don't mind if I have to use ActiveXObjects.

An answer ...

  1. Decode the base64-encoded data into a string using my base64.js or similar.
  2. Create an ADODB.Stream object, configure it for Text Mode (2) and the ISO-8859-1 Charset.
  3. Finally call WriteText() followed by SaveToFile() and Close().

Warning: This will only work on Windows machines running Internet Explorer (or another ActiveX-capable web browser). It will also be suppressed unless the website it is running from is set as Trusted or the user specifically allows the actions.

Example ...

var data = DecB64(base64_encoded_string);
var stream = new ActiveXObject("ADODB.Stream");
stream.Type = 2; // text
stream.Charset = "ISO-8859-1";
stream.Open();
stream.WriteText(data);
stream.SaveToFile("C:\\Whatever.dat", 2);
stream.Close();

References ...


Simple JavaScript / AJAX Optimizations

Often people encounter performance problems in largish JavaScript/AJAX applications and just write it off as a hazard of the language. There are several techniques, however, which can alleviate a lot of common bottle-necks. Depending on the situation you may not be able to take advantage of all of them, but any one of them can be a huge help.

My Background: I use JavaScript extensively in server-side processes and workstation tasks on Windows with Windows Scripting Hosting (and Microsoft's JScript implementation), so I naturally know more about the short comings of that environment as opposed to SpiderMonkey/FireFox.

Use Array for large/long string building:

If you're a .NET developer you're familiar with the StringBuilder which you know to use instead of adding strings together with the plus sign. In JavaScript I encourage you to do something similar and push the strings to an Array, then join the elements at the end. JScript/Internet Explorer users will thank you because Microsoft's implementation is ungodly slow (SpiderMonkey/FireFox users will be delighted that plus-sign concatentation is actually faster by a small margin). In Windows with JScript, every time you concatenate a string to another string it will allocate a third string, copy the contents of both source strings into it, and then destroy the old string. In long loops, this can get so slow that a web browser or command script will completely hang near-indefinitely.

For small strings, especially those not in a loop of some kind, using plus-sign concatenation is just fine. Maybe some day this won't matter, because JScript/Internet Explorer will get fixed!

Use charCodeAt() instead of charAt():

The best place to put this into practice is anytime you're comparingindividual characters, not appending them to a string. The difference being that you're getting back a Number (the character code) rather than a String (the character itself). JavaScript has no single-character type (yes it does have types underneath its sexy var's).

In the JScript implementation on Windows this must not only allocate a VARIANT but also a BSTR.

Use RegExp::exec instead of String::match:

There's good and bad to this. The good is that you create a single RegExp object and subsequent uses don't incur regular expression compilation/syntax checks (assuming, of course, that you're not creating the RegExp object in your loop or function ... you aren't are you?). The bad is that you can't use the nifty global (g) flag; exec will only find the first match and stop. This makes it a wee bit faster but that doesn't matter if you need to find N matches.


Contact

Comments or questions? Email me at webmaster@neilstuff.com.