Christian Sciberras suggested a solution that depended on modifying the HTML source to include a hidden input field and modifying the function stores its result in the field. I've wanted a tidier solution that didn't involve changing either the HTML code or the JavaScript function, because we can't always do that.

I've now got a solution based on Christian's:

Create a hidden input field in the current document with a unique id.

Wrap the required function call in JavaScript that calls the function and stores its return value in the input field.

Read the value from the input field and return it.

It's a bit of a dirty hack, and it only works if the function's return value can be represented as a string. For what it's worth, here it is:

GetRetValContainer tries to find the hidden input field and, if it doesn't exist, calls CreateRetValContainer. This method manipulates the DOM to append a hidden input field to the current document. In this way repeated calls to JavaScript function re-use the hidden field once it has been created.

RunJSProc just calls a JavaScript function without getting its return value. It is useful when no return value is needed or available.

RunJSFn is where the action is. The key is the use of the JavaScript eval function to store the function result in the hidden input. It finds the field from its id and stores the function result its value attribute. RunJSFn then gets its return value from the field.

Finally, we use a GUID as the id of the hidden input field to try to ensure it is unique in the document:

constcRetValElemId='id58A3A2A46539468A943D00FDD6A4FF08';

So there we have it - at last a way to get a value from a JavaScript function. But, what about functions that don't return values that make sense when cast to strings: what if the function returns an object such as Date? Leave a comment if you have ideas please.

This source code, along with a demo project for Delphi 2010 is available in my Delphi Doodlings repository. View the code.

If you're wandering about that UniqueString stuff, check out this post.

The assumption was that CreateProcessW would expect a Unicode environment block. Wrong! It actually still expects an ANSI block by default.

A dig around in the API docs revealed the answer: If you pass a Unicode environment block to CreateProcess in the lpEnvironment parameter you must also include CREATE_UNICODE_ENVIRONMENT in the dwCreationFlags parameter. So it's just a matter of changing

"the data should first be encoded as octets according to the UTF-8 character encoding [STD63]; then only those octets that do not correspond to characters in the unreserved set should be percent-encoded."

So, we define the URIEncode function to operate on the UTF8String type. It's easy to encode UnicodeString and AnsiString into UTF using the System unit's UTF8Encode overloaded functions. You can overload URIEncode to do the UTF8 conversion, but I haven't done here.

There's a nice shortcut we can take when url encoding. Remember only unreserved characters are percent-encoded. The set of unreserved characters is:

All other characters are percent encoded. But what about any UTF-8 continuation bytes? Well, by definition these have value > $80. And all the unreserved characters have ordinal value < $80. This means that no legal continuation character can be an unreserved character.

Therefore any byte in the UTF-8 string can be treated the same regardless of whether it's a lead or continuation character: i.e. we percent encode it if it's not an unreserved character.

Here's the function:

// Assumes Defined(UNICODE)functionURIEncode(constS:UTF8String):string;overload;varCh:AnsiChar;begin// Just scan the string an octet at a time looking for chars to encodeResult:='';forChinSdoifCharInSet(Ch,cURLUnreservedChars)thenResult:=Result+WideChar(Ch)elseResult:=Result+'%'+IntToHex(Ord(Ch),2);end;

This, and more similar routines, are available (and may even be evolving) in my Delphi Doodlings repo. View the code (see UURIEncode.pas).