Dim strID
strID = obj.GetID
John Crim
WebGecko Software
jo...@webgecko.com
http://www.webgecko.com
johnf <jo...@worldcyberlinks.com> wrote in message
news:7o5q2s$r...@dfw-ixnews16.ix.netcom.com...
> Does anybody know how to get VBScript to pass a reference to a variable to
> my script object methods?
...
> my IDL file has :
> int GetID([out,retval]BSTR* ID);
John Crim wrote in message ...
>
>The proper VBScript syntax for retrieving an [out, retval] is:
>
>Dim strID
>strID = obj.GetID
>
>John Crim
>WebGecko Software
>jo...@webgecko.com
>http://www.webgecko.com
>
>johnf <jo...@worldcyberlinks.com> wrote in message
>news:7o5q2s$r...@dfw-ixnews16.ix.netcom.com...
>> Does anybody know how to get VBScript to pass a reference to a variable
to
>> my script object methods?
>...
Hey there,
VBScript only supports [out] parameters if they are VARIANTs. And I think
they have to be [in, out] as well (although you can try without first).
Peter
--
Peter Torr - pt...@microsoft.com
Microsoft Windows Script Program Manager.
http://msdn.microsoft.com/scripting
1) multiple [in] parameters with parameters types that are oleautomation
compatible (not necessarily an explicit VARIANT)
2) single [out,retval] that is oleautomation compatible (not necessarily an
explicit VARIANT)
3) other out-bound parameters are possible, but they must be [in,out]
VARIANT*
Avoid [out] VARIANT* due to know leak issues with VB
One more note: Java does not like any out-bound unless it is [out,retval].
Peter Partch
Peter Torr (MS) <pt...@microsoft.com> wrote in message
news:#i1hWUc3#GA.55@cppssbbsa05...
some of my IDL attempts:
HRESULT GetIDS([in,outl]VARIANT* ID1, [in,out]VARIANT* ID2);
HRESULT GetIDS([in,outl]VARIANTARG* ID1, [in,out]VARIANTARG * ID2);
HRESULT GetIDS([inl]VARIANT ID1, [in]VARIANT ID2);
HRESULT GetIDS([in,outl]BSTR* ID1, [in,out]BSTR* ID2);
> However, after trying everybodies suggestions, I am still seeing the
script
> engine send me a Variant (via IDispatch) with a subtype of VT_BSTR (no
> VT_BYREF) if the variable is preloaded with a string, or a subtype of
VT_I4
> (again no VT_BYREF) if a integer is loaded.
OK, but you are not asking for a VT_BYREF BSTR, you are asking for an [in,
out] VARIANT. So what you should have is something like this:
// ---*---*---*---*---*---*
[id(1), helpstring("Returns two things (VBScript only)")]
HRESULT GetStuff(
[in, out] VARIANT *First,
[in, out] VARIANT *Second);
// ---*---*---*---*---*---*
STDMETHODIMP CInOut::GetStuff(VARIANT *First, VARIANT *Second)
{
// Do anything with passed-in data here...
VariantClear(First);
VariantClear(Second);
// Unneccesary if they were already BSTRs
First->vt = VT_BSTR;
Second->vt = VT_BSTR;
// Put new strings in place
First->bstrVal = SysAllocString(L"This is the first parameter");
Second->bstrVal = SysAllocString(L"This is the second parameter");
return S_OK;
}
// ---*---*---*---*---*---*
Given that function, the following VBS file:
// ---*---*---*---*---*---*
Dim o
Dim s1
Dim s2
Set o = WScript.CreateObject("InOut.InOut")
s1 = "Mary had a little lamb"
s2 = "Its fleece was white as snow"
WScript.Echo "Before:"
WScript.Echo "s1 = " & s1
WScript.Echo "s2 = " & s2
o.GetStuff s1, s2
WScript.Echo "After:"
WScript.Echo "s1 = " & s1
WScript.Echo "s2 = " & s2
// ---*---*---*---*---*---*
Produces this output:
// ---*---*---*---*---*---*
Before:
s1 = Mary had a little lamb
s2 = Its fleece was white as snow
After:
s1 = This is the first parameter
s2 = This is the second parameter
// ---*---*---*---*---*---*
So there you have it! And you can use the debugger to see the the strings
are passed to the function OK.
Here's a slightly better implementation to deal with VB:
STDMETHODIMP CInOut::GetStuff(VARIANT *First, VARIANT *Second)
{
BSTR *pbstr1, *pbstr2;
if ((First->vt & VT_BYREF) != 0)
{
pbstr1 = First->pbstrVal;
pbstr2 = Second->pbstrVal;
SysFreeString(*pbstr1);
SysFreeString(*pbstr2);
}
else
{
VariantClear(First);
VariantClear(Second);
First->vt = VT_BSTR;
Second->vt = VT_BSTR;
pbstr1 = &(First->bstrVal);
pbstr2 = &(Second->bstrVal);
}
*pbstr1 = SysAllocString(L"This is the first parameter");
*pbstr2 = SysAllocString(L"This is the second parameter");
return S_OK;
}
Peter
In the end, the very fine people at Stingray, who make Objecttive
Toolkit Pro (which has an ActiveX Scripting Host Framework) helped me
to get this to work..
Try something like the following for passing a string by reference
into a C++ method from VBScript. After echoing the string passed in,
it then modifies it and passes it back to the script!
I should think it will work for multiple parameters. I can't see why
it wouldn't. BTW, you can pass arrays too. Perhaps this is what you
really need to do.
Look for Knowlege Article ID Q165967
"PRB: Scriopt Error Occurs When Referencing Non-variant Array"
This should help you. If not, e-mail me. Your e-mail address seems
invalid.
I am not sure of the impact / compatibility with VBA and VB...
Regards,
.odl entry
[id(14)] short Test([in,out]VARIANT* name);
.h include file entry
afx_msg short Test(VARIANT FAR* name);
.cpp file map and implementation
DISP_FUNCTION(CAutoClass, "Test", "Test", VT_I2, VTS_PVARIANT)
short CAutoClass::Test(VARIANT FAR* name)
{
// TODO: Add your dispatch handler code here if(name->vt == VT_BSTR)
{
CString strNewMsg = "This is my new String";
CString strOldMsg = name->bstrVal;
SysFreeString(name->bstrVal);
MessageBox(NULL, strOldMsg, _T("MFCObj Message"), MB_OK);
MessageBox(NULL, strNewMsg, _T("MFCObj Message"), MB_OK);
VariantClear(name);
name->vt = VT_BSTR;
name->bstrVal = strNewMsg.AllocSysString();
}
return 0;
}
On Tue, 3 Aug 1999 12:11:23 -0400, "johnf" <jo...@worldcyberlinks.com>
wrote:
>Does anybody know how to get VBScript to pass a reference to a variable to
>my script object methods?
>The VBScript statements:
>Dim var1="name"
>MyObject.GetID(name)
>MsgBox(name)
>will send my script object (via IDispatch) a VARIANT with a type of VT_BSTR
>with the BSTR val="name", Changing the BSTR has no effect. With MsgBox
>displaying "name"
>While,
>Dim var1=1
>MyObject.GetID(name)
> will send my script object a VT_I4 with 1 as the IVal
>my IDL file has :
>int GetID([out,retval]BSTR* ID);
> VariantClear(name);
> name->vt = VT_BSTR;
> name->bstrVal = strNewMsg.AllocSysString();
This will work for VBScript, but as I found with my first example, it won't
work for VB because it uses VT_BYREF. So you have to do a conditional (like
my other post, but perhaps a bit more robust ;-) ).
My real C++ routines generally perform a VariantClear operation, before they
populate the variable passed into the routine from the script. However,
there may be some issues as to who is performing the memory release. The
whole memory freeing issue with COM has me abit confused..
Peter Torr (MS) wrote in message ...
<ernst...@mindspring.com> wrote in message
news:7o8455$li3$1...@nntp4.atl.mindspring.net...
> This is wonderful. Thank you.. Personally, I don't know the subtlety in
the
> conditional test in your sample. If you have some extra time people will
> probably benefit from the why.
OK, what the conditional does it check to see if the VARIANT has the
VT_BYREF flag set. If this flag is set, then the VARIANT doesn't hold the
data itself, but instead holds a pointer to the data. For example, if the
VARIANT's vt is only VT_BSTR, then the bstrVal member holds a BSTR (which is
an OLECHAR* (or unsigned short *) type).
But if vt is VT_BSTR | VT_BYREF, then bstrVal is meaningless, and pbstrVal
holds a pointer to a BSTR (so it is OLECHAR ** (or unsigned short **)). If
you over-write the Variant - even using VariantClear() - it doesn't do
anything because the actual data is held somewhere else.
So the conditional checks if VT_BYREF is specified (doing a bit-wise AND and
checking that the result is non-zero) to see if it should look at bstrVal or
pbstrVal. Note that this is not really very robust coding - it could have
been a VT_I4 with the ByRef bit set, so I should really have checked for
VT_BSTR as well... ;-)
> My real C++ routines generally perform a VariantClear operation, before
they
> populate the variable passed into the routine from the script. However,
> there may be some issues as to who is performing the memory release. The
> whole memory freeing issue with COM has me abit confused..
OK, the basic rules are:
* For [in] parameters, don't touch anything. The caller allocates the data,
then frees it when the method returns. If you need to store the data in any
way, you must make a copy of it (not just a copy of the pointer!) - eg with
SysAllocString or VariantCopy.
* For [out] parameters, you allocate the data, but don't free it (obviously
;-) ). In particular, you can't return data members or stuff like that
(unless they are primitives - ints, longs, etc) - you must copy them (again
using SysAllocString or VariantCopy).
* For [in, out] data, you can either leave it alone, or free it and then
re-allocate it later on. But you can't free it without re-allocating it
(unless you explicitly put it to NULL) because the caller will expect to
have to free the data later on.
Note that it is *probably* a good idea to clear out the data passed for an
[out] parameter (eg, SysFreeString / VariantClear / etc. as long as it isn't
NULL), but I *think* that the caller is supposed to have done this for you
[note I'm a Program Manager on the Scripting team and not a developer on the
COM team ;-) ]
Does this help?
Hi Peter,
It's not really the case of "in general". It is really only if you are
talking about access by Script - you can have as many [out] parameters as
you want, of any automation-compatible type. For example:
[id(2), helpstring("Lots of output params")]
HRESULT LoadsaOuts(
[out] short *Num1,
[out] long *Num2,
[out] BSTR *Text);
// --------------
STDMETHODIMP CInOut::LoadsaOuts(short *Num1, long *Num2, BSTR *Text)
{
*Num1 = 1234;
*Num2 = 5678;
*Text = SysAllocString(L"Where do you want to go today?(TM)");
return S_OK;
}
// --------------
This code works fine with VB, and should work with any other automation
controller (except script). Having said that, it is always a good idea to
design your code so that it is accessible from script, although if there is
no need to do this, then you can mix [out] parameters, support multiple
interfaces, etc.
So when I said "In General" I was referring to a interface definition that
can be used by the widest possible range of scripting clients.
Also since this message is being posted to the script hosting newsgroup,
then yes, I'm limiting my previous comment to ActiveX Scripting
environments.
Peter Partch
Peter Torr (MS) <pt...@microsoft.com> wrote in message
news:udew33i3#GA.232@cppssbbsa04...
If I were to stipulate that my clients (VB or VBScript) pass by
reference a variant variable, then would I need to be concerned about
this? As long as I get a pointer to a Variant, my method will probably
change it for return to the script to suit the needs of the
client/server contract (in my case, my C++ code is hosting the
scripting engine, and not knowing any better, I committed to one
design/implementation which may not be optimal / robust, but it works.
Let me explain:
As for the VariantClear, I'm assuming (in my C++ code that is called
from the script) that what is passed in is potentially garbage (ie,
I'm not getting a pointer to a variant flagged VT_EMPTY). Infact a
client may sloppily supply me with a variant that is VT_I4, when what
I expected was something flagged VT_ARRAY. Now I have some choices, I
could generate a run-time exception, or return an error status, or I
can allow the routine to proceed. I chose the latter.
In this case, my C++ method returns a variant which is flagged
VT_ARRAY if and only if there was something to populate it with (ie
data). If not, I figure I have to provide the client with an
indication that what it expects to be a variant array for accessing
information (using collection semantics or array indexing ) is going
to be problematiic. In that case (no data to return), I flag it
VT_EMPTY so the VBScript can perform either IsEmpty() or IsArray()
testing before proceeding to access the array.
This may not be a good way to go, but to be honest, I didn't have alot
of time or information to make better decisions.
As for not being a developer on the COM team, you're supplying very
useful information which I haven't seen elsewhere. It is very
appreciated.
Any additional tips from those knowledgeable about this would also be
appreciated.
Best Regards
On Tue, 3 Aug 1999 19:53:29 -0700, "Peter Torr \(MS\)"
<pt...@microsoft.com> wrote:
>Hey there,
>
[..stuff deleted]
>OK, the basic rules are:
>
>* For [in] parameters, don't touch anything. The caller allocates the data,
>then frees it when the method returns. If you need to store the data in any
>way, you must make a copy of it (not just a copy of the pointer!) - eg with
>SysAllocString or VariantCopy.
>
>* For [out] parameters, you allocate the data, but don't free it (obviously
>;-) ). In particular, you can't return data members or stuff like that
>(unless they are primitives - ints, longs, etc) - you must copy them (again
>using SysAllocString or VariantCopy).
>
>* For [in, out] data, you can either leave it alone, or free it and then
>re-allocate it later on. But you can't free it without re-allocating it
>(unless you explicitly put it to NULL) because the caller will expect to
>have to free the data later on.
>
>Note that it is *probably* a good idea to clear out the data passed for an
>[out] parameter (eg, SysFreeString / VariantClear / etc. as long as it isn't
>NULL), but I *think* that the caller is supposed to have done this for you
>[note I'm a Program Manager on the Scripting team and not a developer on the
>COM team ;-) ]
>
>Does this help?
>
As long as the IDL says that the parameter is [out] (possibly with other
modifiers like [in] or [retval]) then you can destroy what is in the
pointed-to data and replace it with whatever you want. One thing I'm trying
to check up on at the moment is whether the VB behaviour is "correct". With
the first bit of code I sent, even though it calls VariantClear() on the
passed-in VARIANT and then fills it with a new string, VB completely ignores
this and continues to use its old string. Because VT_BYREF is set,
VariantClear doesn't free the pointed-to string (which I guess is the
correct behaviour), but then VB never checks to see if the VT_BYREF flag is
still set when the function returns.
The Automation docs have this to say in the "Variant Manipulation API
Functions" section:
For VT_BYREF | any type, the memory pointed to by the variant is owned and
freed by the caller of the function
...which suggests you shouldn't free and then re-allocate it, but that's
*exactly* what you want to do if you have an [in, out] parameter. I'm trying
to find out more about this (eg, is it a documentation bug, a VB bug, or
what?).
> As for the VariantClear, I'm assuming (in my C++ code that is called
> from the script) that what is passed in is potentially garbage (ie,
> I'm not getting a pointer to a variant flagged VT_EMPTY). Infact a
> client may sloppily supply me with a variant that is VT_I4, when what
> I expected was something flagged VT_ARRAY.
Actually, this is expected behaviour, not really "sloppy". If your method is
specified as taking a VARIANT, then the client cannot possibly know what
sub-type of VARIANT you want. Also, if it is specified as [out] only, then
the client doesn't care (and neither should you) what is actually in the
VARIANT at the time it calls your method, because it knows you are going to
kill it.
> In this case, my C++ method returns a variant which is flagged
> VT_ARRAY if and only if there was something to populate it with (ie
> data). If not, I figure I have to provide the client with an
> indication that what it expects to be a variant array for accessing
> information (using collection semantics or array indexing ) is going
> to be problematiic. In that case (no data to return), I flag it
> VT_EMPTY so the VBScript can perform either IsEmpty() or IsArray()
> testing before proceeding to access the array.
You should use the OLE Error reporting mechanisms; I'm sure at least one of
the bits of code at http://www.netspace.net.au/~torrboy/code/ does this (I
think JSafeArray does it). If not, I know I have the code sitting around in
my still-as-yet-incomplete nice error component, so I can post it if
required. Essentially, you mark your ATL component as supporting
ISupportErrorInfo, and then when you get an error you call CreateErrorInfo
and play around with it a bit.
> As for not being a developer on the COM team, you're supplying very
> useful information which I haven't seen elsewhere. It is very
> appreciated.
Well, hopefully it is accurate ;-) That's what the disclaimer was more
about... I'm posting stuff that "works", but please don't take it as
"Microsoft gospel" just because I happen to work here! I'm just as likely to
screw up as the next person, I'm afraid.
> Any additional tips from those knowledgeable about this would also be
> appreciated.
You would probably be better off asking in-depth questions in a COM
newsgroup, but if anyone can add to this discussion, it would be good (I
think it is still "on-topic" because it has to do with dealing with C++ /
Script interaction).
> So when I said "In General" I was referring to a interface definition that
> can be used by the widest possible range of scripting clients.
Sure; I just wanted to point out that, as far as the rules of Automation go,
you're not limited quite as much as you are with script.
> Also since this message is being posted to the script hosting newsgroup,
> then yes, I'm limiting my previous comment to ActiveX Scripting
> environments.
Cool; again, I just wanted to make it a bit clearer for anyone else.
Thanks,
Hi Samuel,
It turns out that the extra steps needed for VB were because I had typed the
variables as Strings in VB. If the variables are typed as Variants, then you
get the same behaviour as VBScript....
But it is probably best to try both approaches because someone is more than
likely to pass a String to a VARIANT ByRef procedure (especially since VB
doesn't complain / warn you about it).
I've encountered similar problem and read your post. After I follow your
steps
to write my code, I always get the runtime error: "Type mismatch ... Scode
800a000d". But if
I use VTS_VARIANT instead of VTS_PVARIANT in DISP_FUNCTION macro, the
runtime error is gone. However, I couldn't pass any data from my C++ code to
VBScript. Am I missing something here?
Here is my code,
in .odl file:
dispinterface IDM
{
properties:
methods:
file://{{AFX_ODL_METHOD(CDMDispatch)
[id(1)] void GetESN([in, out] VARIANT* esn);
file://}}AFX_ODL_METHOD
};
in .h file:
afx_msg void GetESN(VARIANT FAR* esn);
in .cpp file:
DISP_FUNCTION(CDMDispatch, "GetESN", GetESN, VT_EMPTY, VTS_PVARIANT)
void CDMDispatch::GetESN(VARIANT FAR* esn)
{
esn->vt = VT_UI4;
esn->ulVal = 0x12345678;
}
Thanks for your help.
Wayne
Samuel Ernst-Fortin <sfo...@searchtech.com> wrote in message
news:37a76663....@news.atl.mindspring.com...
> VariantClear(name);
> name->vt = VT_BSTR;
> name->bstrVal = strNewMsg.AllocSysString();
> }
May I recommend as a test that you modify your ODL, h, and cpp files so that
your method returns a short. Then, use the following in your script:
Dim status, value
status = ____.GetESN(value)
where ____ is the objectname exposed to the script that handles calls to
this CDMDispatch method. You are instantiating an instance of the automation
class and exposing it to the script via AddTopLevelItem(), right?
You should be able to cut and paste my example into your code, and verify
that works. If it doesn't, you have some other problem that must be cleared
up.
Wayne wrote in message ...
I want to be able to set the parameters passed in through the following
function from Microsoft's TreeView control.
void OLEDragOver(
[in, out] DataObject** Data,
[in, out] long* Effect,
[in, out] short* Button,
[in, out] short* Shift,
[in, out] single* x,
[in, out] single* y,
[in, out] short* State);
It seems I am not able to do this from script code. Is this true or
is there a way to do it?
Thanks in advance,
Paul
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
Hi there,
You won't be able to do this because the data types are not supported by
script.
VBScript only supports [in, out] parameters if they are VARIANTs, and
JScript doesn't support [out] parameters at all (other than [retval]).
Peter
--
Peter J. Torr - Microsoft Windows Script Program Manager
pt...@microsoft.com - http://msdn.microsoft.com/scripting/
Please do not e-mail me with questions - post them to this
newsgroup instead. Thankyou!