Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call a function written on VB from a JScript code (classic ASP)

Currently I have to deal with the legacy system written in VB. I'm not good with VB and ASP, so I decided that new code for this system will be written in JScript.

However, there is some problem with interoperability between the two languages: namely, when I'm trying to call some function declared in <script language="vbscript"> tag, it fails with a "Object expected" error (if the page language is VBScript), and vice versa.

Namely, the following code:

inc.asp

<script language="vbscript" runat="server">
Sub VBTestFunction(Message)
    Response.Write "VBTestFunction: " & Message
End Sub
</script>
<script language="javascript" runat="server">
function JSTestFunction(Message) {
    Response.Write("JSTestFunction: " + Message);
}
</script>

testjs.asp

<%@ Language="JavaScript" %>
<!-- #include file="inc.asp"-->
<script language="javascript" runat="server">
    VBTestFunction("from javascript");
    JSTestFunction("from javascript");
</script>
<script language="vbscript" runat="server">
    Call VBTestFunction("from vbscript")
    Call JSTestFunction("from vbscript")
</script>

fails with the following error:

VBTestFunction: from vbscript
Microsoft VBScript runtime error '800a000d'
Type mismatch: 'JSTestFunction'
/test.asp, line 9

(if I'll comment the specific line, other three statements will work fine); setting the page language to VBScript

<%@ Language="VBScript" %>
<!-- #include file="inc.asp"-->
<script language="javascript" runat="server">
    VBTestFunction("from javascript");
    JSTestFunction("from javascript");
</script>
<script language="vbscript" runat="server">
    Call VBTestFunction("from vbscript")
    Call JSTestFunction("from vbscript")
</script>

fails with the following error:

Microsoft JScript runtime error '800a138f'
Object expected
/test.asp, line 4

(again, if i'll comment out the specific line, other three statements will work fine).

There is an MSDN article on mixing VB and JS in the same application, but from the article it seems that the example code should work, as TestFunction is declared in another file and is a function after all.

Is there some way to make all this thing working, and to call both VBTestFunction and JSTestFunction from both VB and JS code? I guess there should be one, otherwise there would be no point in mixing JS and VB.

like image 512
penartur Avatar asked Apr 10 '12 05:04

penartur


2 Answers

I've been monitoring this question for a while and Salman has pretty much answered it but there are some things that could be clarified. First of all there is key problem with the article being referenced. It says that the order of execution is this:-

1.Script in elements in nondefault languages
2.Inline script
3.Script in elements in the default language

Its wrong, or at least its out of date (it does after all reference IIS4). The "inline script" (that is script in the default language) is not treated any differently than script elements of the same language.

Here is how to reason through what is happening.

  • Before any parsing begins all the include points are resolved and replaced by content from the include files to create a single lexical "file". This is created before any parsing takes place.

  • Script code is collected from this "file" for each language. You can imagine multiple files (one per language) being appended to as each chunk is found. Note that this is the reason why <% %> and <script runat="server" for the default language are practically indistiguishable.

  • Any static content (that is content outside of a runat="server" script tag or <% %>) is considered to be part of the code for the default language. A special form of Response.Write that sends the static content bytes verbatim to the response is created and appended to the default language code at the point it was found in the original file.

  • Now we have one or more scripts that are ready to be processed by their respective script engines. The non-default language scripts are parsed and executed first. Any global identifier created, be that for a function or a variable, is added to the script environment. However since the default language script has not been processed at all at this point nothing that it might subsequently add to the global script environment is yet available.

  • By the time the default language script is parsed and executed all the global identifiers created by the previous language scripts will have been added to the script environment and are therefore available for use from inline code.

You should note carefully that a default language function can be called by code in a function in the non-default language on the condition that call into the non default function can be traced back to the inline execution of the default language.

For example if the default language is JScript you can have a VBScript function (fnA) call a function declared in JScript (fnB) as long as the call to fnA is made as part of the inline execution of JScript. IOW JScript can call into VBScript which in turn can call into VBScript and so on, the limiting factor is the engine that the top of this chain must be JScript in this scenario.

In your example code you had code at the global (inline) level of your VBScript attempting to call a function declared in the default JScript language. If you follow the above bullets you will see that at the point it is executed the the function being called does not exist.

like image 75
AnthonyWJones Avatar answered Nov 13 '22 19:11

AnthonyWJones


I encourage you not to mix scripting languages. In the article you mentioned, there is a heading titled "Server Script Order of Execution" where it says:

... However, you are then at the mercy of the order of execution of the IIS ASP processor. For example, if you create server script and run it in IIS 4.0, you'll find this execution order:

  1. Script in <SCRIPT> elements in nondefault languages
  2. Inline script
  3. Script in <SCRIPT> elements in the default language

Keeping that in mind, here is how your testjs.asp script is executed, comments indicate execution order:

<%@ Language="JavaScript" %>
<script language="vbscript" runat="server">
    '' #1
    Sub VBTestFunction(Message)
        Response.Write "VBTestFunction: " & Message
    End Sub
</script>
<script language="javascript" runat="server">
    // #3
    function JSTestFunction(Message) {
        Response.Write("JSTestFunction: " + Message);
    }
</script>
<script language="javascript" runat="server">
    // #4
    VBTestFunction("from javascript");
    JSTestFunction("from javascript");
</script>
<script language="vbscript" runat="server">
    '' #2
    Call VBTestFunction("from vbscript")
    Call JSTestFunction("from vbscript")
</script>

Notice the line that causes error:

Call JSTestFunction("from vbscript")

Its execution order is #2; at this point the function JSTestFunction is not defined (it is defined later in the execution order).

Now for testvbs.asp file:

<%@ Language="VBScript" %>
<script language="vbscript" runat="server">
    '' 3
    Sub VBTestFunction(Message)
        Response.Write "VBTestFunction: " & Message
    End Sub
</script>
<script language="javascript" runat="server">
    // 1 
    function JSTestFunction(Message) {
        Response.Write("JSTestFunction: " + Message);
    }
</script>
<script language="javascript" runat="server">
    // 2
    VBTestFunction("from javascript");
    JSTestFunction("from javascript");
</script>
<script language="vbscript" runat="server">
    '' 4
    Call VBTestFunction("from vbscript")
    Call JSTestFunction("from vbscript")
</script>

The line that causes error:

VBTestFunction("from javascript");

Again, VBTestFunction is called before it is defined. The solution is to try not to mix scripting languages. If it is absolutely necessary, revise the order of your scripts.

Edit -- Example

If you have set @ Language="JavaScript" then this code should work as expected:

<!-- inc.asp-->
<script language="vbscript" runat="server">
    Sub VBTestFunction(Message)
        Response.Write "VBTestFunction: " & Message
    End Sub
</script>
<%
    function JSTestFunction(Message) {
        Response.Write("JSTestFunction: " + Message);
    }
%>

<!-- testjs.asp -->
<%@ Language="JavaScript" %>
<!-- #include file="inc.asp"-->
<%
    // at this point, both functions are available
    VBTestFunction("from inline JavaScript");
    JSTestFunction("from inline JavaScript");
%>

If you want to use @ Language="VBScript" then you have to re-arrange all code:

<!-- inc.asp-->
<script language="javascript" runat="server">
    function JSTestFunction(Message) {
        Response.Write("JSTestFunction: " + Message);
    }
</script>
<%
    Sub VBTestFunction(Message)
        Response.Write "VBTestFunction: " & Message
    End Sub
%>

<!-- testvbs.asp -->
<%@ Language="VBScript" %>
<!-- #include file="inc.asp"-->
<%
    ' at this point, both functions are available
    VBTestFunction("from inline VBScript")
    JSTestFunction("from inline VBScript")
%>
like image 25
Salman A Avatar answered Nov 13 '22 17:11

Salman A