Search code examples
javascriptvbscriptcompiler-errorstype-mismatch

Need help converting vbs code to jscript. Im getting a Runtime Error Type Mismatch


Ive got this labratory equipment that is connected to my PC. It uses special OCX file to communicate with the device (reading, setting parameters and such). I got this code from manual that seems to be working. I get a message box saying "Magnification =1272.814 Last error=API not initialized".

<HTML>
<HEAD>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub window_onLoad()
Dim Value
Dim er
call Api1.Initialise("")
call Api1.Get("AP_MAG",Value)
call Api1.GetLastError(er)
call window.alert("Magnification = " + CStr(Value)+"Last error="+er)
call Api1.ClosingControl()
end sub
-->
</SCRIPT>
<TITLE>New Page</TITLE>
</HEAD>
<BODY>
<object classid="CLSID:71BD42C4-EBD3-11D0-AB3A-444553540000" id="Api1">
<PARAM NAME="_Version" VALUE="65536">
<PARAM NAME="_ExtentX" VALUE="2096">
<PARAM NAME="_ExtentY" VALUE="1058">
<PARAM NAME="_StockProps" VALUE="0">
</OBJECT>
</BODY>
</HTML>

So because I have 0% knowledge in vbs and about 10% in jscript I`m trying to rewrite the same thing in Javascript. And I also have some necessary code already written in js.

<script language="JScript">
var Api1=new ActiveXObject("ApiCtrl");
var value;
var er;
Api1.Initialise("");
Api1.Get("AP_MAG",value);
Api1.GetLastError(er);
window.alert("Magnification = " + value+"\n Last error="+er);
Api1.ClosingControl(); 
</script>

Unfortunately I get a type mismatch error in either .Get or .GetLastError methods either with var value; var er; or var value=""; var er="";

Here is what API manual has to say

long GetLastError(VARIANT* Error)

[out] Error is the error string associated with the error code for the last error Remarks: This call will return a VT_BSTR VARIANT associated with the last error. Return Value: If the call succeeds, it returns 0. If the call fails, an error code is returned from the function.

long Get(LPCTSTR lpszParam, VARIANT* vValue)

[in] lpszParam is the name of the parameter e.g. “AP_MAG”
[in][out] vValue is the value of the parameter Remarks: This call will get the value of the parameter specified and return it in vValue. In C++, before calling this functions you have to specify the variant type (vValue.vt) to either VT_R4 or VT_BSTR. If no variant type is defined for vValue, it defaults to VT_R4 for analogue parameters (AP_XXXX) and VT_BSTR for digital parameters (DP_XXXX). If the variant type is VT_R4 for an analogue parameter, then the floating point representation is returned in the variant. If a VT_BSTR variant is passed, analogue values are returned as scaled strings with the units appended (e.g. AP_WD would return “= 10mm”). For digital parameters, VT_R4 variants result in a state number and VT_BSTR variants result in a state string (e.g. DP_RUNUPSTATE would return state 0 or “Shutdown” or the equivalent in the language being supported). In C++, if the variant type was specified as VT_BSTR then the API will internally allocate a BSTR which the caller has to de-allocate using the SDK call ::SysFreeString (vValue.bstrVal)


Solution

  • Welcome to StackOverflow!

    Well, each language is made with purpose. Then come to deal with ActiveX objects in browser (or WSH) environment, VBScript is the best choice, while JavaScript is most worst.

    JavaScript hasn't so-called out parameters. That mean all function arguments are passed by value (as copy). Lets show you this with examples.

    ' VBScript
    Dim X, Y
    X = 1
    Y = 2
    Foo X, Y
    MsgBox "Outer X = " & X & ", Y = " & Y
    '> Local args: 6, 8
    '> Outer X = 1, Y = 8
    
    Sub Foo(ByVal arg1, ByRef arg2)
        arg1 = 6
        arg2 = 8
        MsgBox "Local args: " & arg1 & ", " & arg2
    End Sub
    

    By default in VBS the arguments are passed by reference, so ByRef prefix in function arguments declaration is optional. I include it for clarity.

    What the example illustrate is the meaning of "by reference" or "out" parameter. It behave like return value because it modify referenced variable. While modifying "by value" variable has no effect outside of the function scope, because we modify a "copy" of that variable.

    // JavaScript
    function foo(arg1) {
        arg1 = 2;
        alert('Local var = ' + arg1);
    }
    var x = 0;
    foo(x);
    alert('Outer var = ' + x);
    
    // Local var = 2
    // Outer var = 0
    

    Now take a look at this thread. Looks like there is a kind of partial solution by using empty objects. I'm not sure in which cases that will work, but for sure it's very limited hack.

    If this not help in your case, then looks like it's time to go with VBScript. Starting with VBS is easy anyway. It's the most user friendly language I ever touch. I was need days, even weeks with other languages only to get started, while just after a few hours with VBS I was able to use it freely.

    [EDIT] Well, I made a lot more efforts to reply as may looks like at the glance :) Starting with the language limitation you met. Afterwards going to explain the nature of that limitation (what's "in/out" parameter), and the best way to do that is via example, and this is what I did. Afterwards I show you the only workaround out there to deal with this limitation in JS. Can we consider this as complete answer?

    You not mention whether you test this "empty-object-trick", but as you still asking I presume you did that and it's not work with your OCX, right? Then, in this case, you're just forced to deal with your OCX via VBScript, what was my answer from the beginning. And as you prefer to stay with JS then you need to integrate a piece of VB code in your solution.

    And as you noted too, this VBs/Js integration is a whole new question. Yes, good question of course, but it's a metter of new topic.

    Ok, lets say that the question you append below: "why it should work with passing objects as a function parameter", is still a part of the main question. Well, as you see, even people using JS daily (am not one of them) has no idea what happens "behind the hood", i.e. do not expect an answer on what the JS-engine do in this case, or how this cheat the JS-engine to do something that it's not designed to do. Personally, as I use JS very rarely and not for such tasks, am not even sure if this trick works at all. But as the JS-guys assert it works (in some cases) then we s'd trust them. But that's all about. If this approach fail then it's not an option.

    Now what's remain is a bit of homework, you s'd research all available methods for VBs/Js integration, also test them to see which one is most applicable to your domain, and if by chance you meet with difficulties, just then come-back to the forum with new topic and the concrete issue you're trying to resolve.

    And to become as helpful as possible, I'll facilitate you with several references to get started.

    Here is the plan...

    1. If it's possible to work without VBs/Js integration then use stay-alone .VBS files (in WSH environment), else ...

    2. In case you work in browser environment (HTML or HTA) then you can embed both (VBs/Js), and your integration w'd be simple.

    3. Or may integrate VBs/Js with Windows Script Files (.wsf).

    4. Or use ScriptControl that allow running VBScript from within JScript (or backward/opposite).

    Links:

    What is Batch-Embeded-Script:

    5. Some other method (if you find, that am not aware of).

    Well, after all this improvements I not see what I can append more, and as I think, now my answer is more than complete. If you agree with my answer then accept it by clicking on the big white arrow. Of course, if you expect to get better reply from other users, you may still wait, but keep in mind that unanswered questions stay active just for awhile and then become closed.