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
VC++
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
VC++
developers
to use it.
Description
To use
either
VBScript
or
JScript
is fairly
simple in a
VB
and
VC++
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.
Collapse
Copy
Code
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:
Collapse
Copy
Code
Function Celsius(fDegrees)
Celsius = (fDegrees - 32) * 5 / 9
End Function
or in
JScript
write:
Collapse
Copy
Code
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.
Collapse
Copy
Code
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:
Collapse
Copy
Code
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); else
{
sfHelper.Create(VT_VARIANT, 1, 0, 1); var = _bstr_t(strParam);
}
sfHelper.PutElement(0, (void*)&var); 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.
-
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.
-
You may
have
your
script
to do a
complete
tucancode.net and
you will
load the
script
file
based on
the tucancode.net
(the
CScriptObject
class
can load
a script
file for
you!).
Example:
This
script
starts
the
"Calculator"
program.
Collapse
Copy
Code
function StartCalc()
{
var WshShell = new ActiveXObject("WScript.Shell");
var oExec = WshShell.Exec("calc");
WshShell = null;
}
-
You may
want to
create
ActiveX
object
that
lives
longer
than for
a
function
call:
Collapse
Copy
Code
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);
}
-
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