Click here to Skip to main content
Email Password   helpLost your password?
Download ScriptDemo Demo Project - 31 Kb

ScreenShots

Introduction

I am always amazed to see how the script control (msscript.ocx) is fun to use and at the same time how C++ developers reacted when it's time to use. Maybe the extension (.ocx) make them feel, it's visual basic! In this article, I would like to remove those frontiers and give some new reasons for C++ developers to use it.

Description

To use either VBScript or JScript is fairly simple in a VB and C++ Application thanks to Microsoft's development efforts to create Windows Scripting technology. A developer only needs to know how to use the Microsoft Scripting ActiveX control (msscript.ocx) and how to pass value to a script method. For this reason, the first wrapper class that I want to identify is the CScriptObject. This wrapper is very simple to use and it provides most of the functionality that you will want to use in your application. It has a function to load script (text data) from a file or resource, get a list of methods name, selecting script language and to the execute function and statement. This class has no dependencies on MFC and can also be used in a console application. 

First of all to call a script it is important to know that VBScript and JScript deal only with VARIANT parameters. This is the reason I created the CSafeArrayHelper class. The CSafeArray helper wrapper class allows you to create parameters that you will pass to your script function.

class CSafeArrayHelper
{
    public:
        CSafeArrayHelper();
        ~CSafeArrayHelper();

    bool Create(VARTYPE  vt, UINT  cDims, UINT lBound, UINT cCount);
    bool Destroy();
    UINT GetDimension();

    bool Attach(LPSAFEARRAY psa);
    bool AttachFromVariant(VARIANT* pVariant);
    LPSAFEARRAY Detach();
    LPSAFEARRAY GetArray();
    bool AccessData(void FAR* FAR* pvData);
    bool UnaccessData();
    bool Lock();
    bool Unlock();
    bool PutElement(long lIndices, void FAR* vData);
    bool GetElement(long lIndices, void FAR* vData);
    VARIANT GetAsVariant();

    protected:
    LPSAFEARRAY    m_pSA;

    private:
};
It provides the exact same features that you will want to use with SAFEARRAY object but its usage may be simpler for some of us (like me!). The function GetAsVariant may be useful in case when you want to view the type of data that was encapsulated in your SAFEARRAY. This function could not provide ways to read all data types since the SAFEARRAY Data type (fFeatures) didn't implement it. Nonetheless to say, this function do a guess on the data types.

How to use

First to use this control, I will recommend you to take a look at the documentation for VBScript and JScript to know all you can do within your script function.

Writing a Script function

Let's say we want to create a simple function to convert temperature from Fahrenheit to Celsius.

In VBScript write:

Function Celsius(fDegrees)
   Celsius = (fDegrees - 32) * 5 / 9
End Function
or in JScript write:
function Celsius(fDegres)
{
   return (fDegres-32)*5/9;
}
To call this function, one only needs to store each parameter into VARIANT. Since your function (method) can have more than one parameter, a SAFEARRAY is needed to encapsulated them. In that latter case, you may want to view the parameter count for the array passed to your function by checking the .length property for string function or by some other means.
function CountParam(aParam)
{
    var strPresent = "Parameter is : " + (aParam.length>0 ? "Present": "Not present");
    return strPresent;
}
The same technique may be used in VBScript. This allows you to detect variable length argument at run time. To call a function without argument, a SAFERRAY is created but without parameter.

Calling a Script function

Your code can be as easy as this:

void CScriptDemoDlg::OnBtnExecute() 
{
    CString strParam, strProc;
    m_ctlParameter.GetWindowText( strParam );
    m_ctlFunctions.GetWindowText( strProc );

    CSafeArrayHelper sfHelper;
    try{
        _variant_t var;
        if (strProc.IsEmpty())
            sfHelper.Create(VT_VARIANT, 1, 0, 0);    // (void) parameter

        else
        {
            sfHelper.Create(VT_VARIANT, 1, 0, 1);    // 1 parameter

            var = _bstr_t(strParam);
        }
        sfHelper.PutElement(0, (void*)&var);    // parameter1 -> index 0

        LPSAFEARRAY sa =  sfHelper.GetArray();
        _variant_t varRet;
        if (m_ScriptObj.RunProcedure(strProc, &sa, &varRet))
            m_ctlResult.SetWindowText( (LPCTSTR)(_bstr_t(varRet)) );
        else
        {
            CString strError = m_ScriptObj.GetErrorString();
            m_ctlResult.SetWindowText( strError );
        }
    }
    catch(...)
    {
        CString strError = m_ScriptObj.GetErrorString();
        m_ctlResult.SetWindowText( strError );
    }
}

Some Ideas

Some of the ideas that you may want to try.
  1. You may want to have your script acts like a plugin, one suggestion is to have a resource script into a DLL and loads it at runtime (you may also have it part of your application). In that case, you will want to have specific module-related function, like: InitModule, ReleaseModule, btnOK_Click, btnCancel_Click, LoadUserData(strUsername), SaveUserData(strUserData), etc... and each of your DLL will have to implement them.

  2. You may have your script to do a complete task and you will load the script file based on the task (the CScriptObject class can load a script file for you!).

    Example: This script starts the "Calculator" program.

    function StartCalc()
    {
     var WshShell = new ActiveXObject("WScript.Shell");
     var oExec = WshShell.Exec("calc");
         WshShell = null;
    }
  3. You may want to create ActiveX object that lives longer than for a function call:
    var XML_Obj;
    function StartModule()
    {
     XML_Obj = new ActiveXObject("Msxml.DOMDocument");
     XML_Obj.async = false;
    }
    function StopModule()
    {
     XML_Obj = null;
    }
    function LoadSettings(strFilename)
    {
     XML_Obj.load(strFilename);
    }
  4. There are cases that you may want to execute the script code directly, just add the code, do not create a function...try it for fun!

References

Microsoft Windows Script Control
VBScript Documentation
JScript Documentation

History

15 July 2002 - updated demo fixed VC6 and VC7 issues

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralAn error happened when the application existed
shengberlin
3:53 24 Sep '09  
An error happened when the application existed, I debuged the program and found it happened in the Decontruction function.
CScriptObject::~CScriptObject()
{
// Destroy object- and release
m_pScript = NULL;
}

error sign
AppName: run.exe AppVer: 1.0.0.1 ModName: msscript.ocx
ModVer: 1.0.0.2604 Offset: 0000b4ba

The error report said the error happened in msscript.ocx.

After I clicked the Close button,it happened:
The "0x00000008" memory referred by "0x6b98b4ba" statemeng was unreadable.

I don't know how to solve it , please help me! Thank you!
GeneralDestroying the SAFEARRAY after an error
Ralf Patzig
23:08 1 Jul '08  
What will happen with the SAFEARRAY passed to the Run of the ScriptControl. Can you really destroy it? I have a similar software part. And even when an error is caught the method SafeArrayDestroy will return a HRESULT unequal to S_OK. What means the ScriptControl is already locking the array. I didn't find a solution, did you?
Best regards.
GeneralRe: Destroying the SAFEARRAY after an error
Ernest Laurentin
5:02 2 Jul '08  
As you are mentioning, the control locks the SafeArray but you can be sure it will be destroyed at some point. You can safely assume it will be destroyed when appropriate.
Cheers,

1. I will develop myself to the maximum of my potential in all ways
2. I will look for the good in all people and make them feel worthwhile.
3. If I have nothing good to say about a person, I will say nothing.
4. I will always be as enthusiastic about the success of others as I am about my own.
5. I will always remain loyal to God, my country, family and my friends - Chuck Norris

Ernest Laurentin

GeneralScript Time Out
ynotyon
8:44 25 Jun '08  
Hi,

In many cases when the script exceeds certain amount of time, I get a timeout error. (This very same script does not time out when running it outside C++). Is it a problem in the microsoft ocx? Is there any solution?

Many thanks,
Yonatan.
GeneralLoadScript problem in a visual C++ thread
victor domingo reguant
7:06 15 Oct '07  
Hi,

There is no problem when I execute a visual basic script inside a function of my application dialog, otherwise the problem arises when I execute the script in a CWinThread process.
The problem is inside the LoadScript function, exactly the following code returns an error:

m_pScript->AddCode(strCode);

inline HRESULT IScriptControl::AddCode ( _bstr_t Code ) {
HRESULT _hr = raw_AddCode(Code);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
}

The _hr value returned is 0x8000ffff, and the GetErrorString() function returns "Error: , ; in line 0", although there is no problem in the script syntax,

Function multiplica(par1,par2)
multiplica = par1*par2
End Function

Can anybody help me?

Thanks in Advance
QuestionLoadScript problem in VC++ thread
victor domingo reguant
7:03 15 Oct '07  
Hi,

There is no problem when I execute a visual basic script inside a function of my application dialog, otherwise the problem arises when I execute the script in a CWinThread process.
The problem is inside the LoadScript function, exactly the following code returns an error:

m_pScript->AddCode(strCode);

inline HRESULT IScriptControl::AddCode ( _bstr_t Code ) {
HRESULT _hr = raw_AddCode(Code);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
}

The _hr value returned is 0x8000ffff, and the GetErrorString() function returns "Error: , ; in line 0", although there is no problem in the script syntax,

Function multiplica(par1,par2)
multiplica = par1*par2
End Function

Can anybody help me?

Thanks in Advance
GeneralMSScript reset trouble.
k01dunn
5:33 29 Aug '07  
Hello.
I have some troubles with MSControl.
When I reset ScriptControl, all Objects and code also cleared.
Can I delete only one Object?Please answer me!
General2 Parameters Again
Peter Weyzen
10:52 28 Apr '07  
I am attempting to use this to do auto-proxy configuration... Here's a sample script:

function FindProxyForURL(url, host)
{
if (isPlainHostName(host))
return "DIRECT";
else
return "DIRECT";
}

I need to pass it 2 parameters. I've tried both calling PutElement with 2 different params, as well as a single comma seperated param.

Regardless, of what I do -- I get a script error:
"Error: Object expected, ; in line 1"

I'm no javascript pro, but the script looks ok.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Peter Weyzen
Staff Engineer
"http://www.soonr.com">SoonR Inc.

GeneralRe: 2 Parameters Again
Ernest Laurentin
12:12 28 Apr '07  
Make sure you call sfHelper.Create(VT_VARIANT, 1, 0, 2);. The current sample initialize only the first parameter.
Hope that helps.
Ernest
GeneralRe: 2 Parameters Again
Peter Weyzen
12:38 30 Apr '07  
Thanks....

Though now think the problem doesn't lie in the scripting interface, but the nature of the auto-proxy detection scripts.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Peter Weyzen
Staff Engineer
"http://www.soonr.com">SoonR Inc.

GeneralHow can I use AddObject and use it.
coronys
5:38 13 Dec '06  
Your application is great and works great also.
Do you consider the use of AddObject.
If you can give a simple code how to use it I will be very happy.
Thanks in advance,
Good job.
GeneralDetermine function parameters
coronys
0:09 7 Dec '06  
Hi,
Excellent job.
Is there a way to retrive the number of parameters that the function needs, and the types?
Also the function return type.
Thanks in advance.
Rose
AnswerRe: Determine function parameters
Ernest Laurentin
16:12 7 Dec '06  
Look at the IScriptProcedure in msscript.tli.
You can get the number of arguments, all types are variant. Same thing for return type.
GeneralRe: Determine function parameters
coronys
20:01 7 Dec '06  
thanks, I will
GeneralGet the source line number
AKSIVAKUMAR
22:08 16 Oct '06  
Hi all,

I want to add VBScripting supports in my C++ application.

We can get the VBScript error info and script error line number using MS Script control.

Is there way to get the particular source line number using microsoft script control ?

Does miscrosoft supports this feature in the mscript.ocx control ?

Please provide information in detail.

Thanks,
Siva


GeneralRe: Get the source line number
AKSIVAKUMAR
0:49 18 Oct '06  
Hey all,

Is there any specific forum where I can post these kind of question to get answer's asap.

I have provide a small VBscript Editor functionality in my VC++ applicaiton using Microsoft Script control.

Here I would like to locate the particular line number of the source text in the VBScript file that I had already added in to the Script Engine. If i send the particular line of source text to the method, it should return the line number. So that i can jump to that particular location and higlight them to the user in the view.

Is there any in-built method or interface available to do this. ? Does miscrosoft supports this feature in the mscript.ocx control ?

Is there way to get the particular source line number using MS Script control or any other methodololgy available ?

If you have any valuable information or suggestions, please provide me in detail.

Regards,
AKS


GeneralProblems with msscript.tlh
xricon
11:00 21 Oct '05  
I´m working with embedded c++, but the example ScriptDemo doesn´t works. It´s give me some errors like:
"msscript.tlh(108) : error C2146: syntax error : missing ';' before identifier '_NewEnum'"



Xime
GeneralRe: Problems with msscript.tlh
Anonymous
14:45 21 Oct '05  
Did you try with Visual Studio 6 or .NET?

I am not sure how embedded c++ will deal with this class.
GeneralRe: Problems with msscript.tlh
Anonymous
5:13 24 Oct '05  
yes I have no problem with Visual Studio .NET, but I need the app running on a PPC Confused
QuestionPassing "binary" data to script...
SonicMouser
4:22 11 Oct '05  
Could someone please explain to me how to pass/return binary data to a script? I tried using wide strings, but, that doesn't work if there happens to be a null in the data (terminates the wide string)

thanks!
andy
AnswerRe: Passing "binary" data to script...
SonicMouser
18:06 11 Oct '05  
Nevermind.. i figured it out....

i used SysAllocStringLen(NULL,dwSize) and it allocated a wide string without putting data in it... then i used MultiByteToWideChar to fill the wide string with the binary data.

I was using Variant type VT_UI8 | VT_ARRAY at first, but then the VBScript has to convert it to VT_BSTR, which eats up alot of time.

So, using the first method i mentioned above seems to be a great way to convert an unsigned char* array (which can contain nulls inside of it) to a valid BSTR which the VBScript can manipulate using basic VB "string" functions e.g.:Len(), Mid(), InStr(), etc... with no extra conversion.

Generalcall application method?
yanba
17:53 4 Oct '05  
Hello there,

I need to call my application method in script,for example:
in my vc++ application:
int CMyApp::myMethod(int i)
{
return i+100;
}
i want call it in script:
function myFunc()
{
var i=myMethod(20);
return i+10;
}

Can someone explain how to do this or send me a sample code?

thanks

Grant Palmer


WWWWWWWWWWWWWW
GeneralRe: call application method?
cederron
13:50 1 Mar '07  
I'm gonna reply, maybe after two years you have already found a solution but anyways...
as far as i know the only way to acomplish what you ask is to make your class implement the IDispatch interface. IDispatch is from COM, so in fact your class has to be a COM object.
Then your class will be directly available to vbscript.
GeneralParameter names
duronebis
8:59 29 Sep '05  
How can I get the parameter names of the function?
I only see a function to get the count, but not the names...

ciao
Stefano

-- modified at 13:59 Thursday 29th September, 2005
GeneralScriptObject not instantiated
Mouad
0:19 21 Jul '05  
Hi all,

I was following this sample of adding Vbscript and Jscript support in VC++ applications.
Using the same ScriptObject in an other project, I always get an exception, saying that object was not created (instantiated) in CScriptObject::CommonConstruct method.

Does anyone have an idea how to get this problem solved ???

Thank you in advance for your help.
Smile Smile Smile


Last Updated 15 Jul 2002 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010