On Thu, 19 Aug 2010, Ludwig, Michael wrote:
> > Quoted from the web:
> >
> >   this looks like an indexed property.  The correct syntax
> >   to assign to them would be
> >
> >     $COMComponent->LetProperty("Value", "Identity", $varUserStr);
> 
> > So I tried the following and it worked:
> >
> >   $xslProc->LetProperty( input => $xmlDoc );
> 
> > I haven't understood the underlying issue, though. Is it that JScript
> > handles different cases transparently that require different syntaxes
> > in Perl and Visual Basic? Pointers welcome.

You are actually *not* dealing with an indexed property here, which
would take an additional index value in addition to the property name.

The issue you are running into is that there are two different mechanisms
to assign to a property, by value, or by reference.  In VB there is different
syntax for both cases:

by value:   Let newVar = oldVar
by ref:     Set newVar = oldVar

The "Let" keyword is optional, so it could also be written as a simple 
assignment:

    newVar = oldVar

Both methods produce the same result when oldVar already is a value: they assign
the value to newVar.  If oldVar is an object, then the "by value" assignment 
will
call the default method on this object (typically, but not always called 
"Value")
and assign that to newVar.  So the "by value" assignment will be

    newVar = oldVar.Value

The "by reference" assignment will just assign a second reference to newVar,
so oldVar and newVar will reference the same object.

Perl does not have a "Set" keyword for "by reference" assignment, and normal
assignments in Perl are also always "by reference" as the concept of calling
a "default" method or property doesn't even exist.  So

    $newVar = $oldVar;

will always assign by reference when $oldVar is an object.  Consequently it
felt most natural/perlish to use the same semantics for OLE property assignment

    $obj->{property} = $other_obj;

You can always turn this into a "by value" assignment by either calling the
default method explicitly (but you have to know its name):

    $obj->{property} = $other_obj->Value;

or use the Win32::OLE::LetProperty() function:

    $obj->LetProperty("property", $other_value);

You rarely need to do this, so the choice of "by reference" assignment for
the default syntax seems to be sensible in retrospect.

The "by value" and "by reference" assignments are implemented by 2 different
COM operation internally: propertyput and propertyputref.  Normally all
OLE properties will implement both, especially if they rely on some automated
framework to implement their IDispatch interface.

You seem to be running into a property that has only implemented propertyput
but not propertyputref, so the default syntax fails for you.  It means
the corresponding code in VBscript would fail too:

    Set xslProc.input = xmlDoc

and only this one would work:

    xslProc.input = xmlDoc

It makes a certain amount of sense to force the user to assign a value and
not an object, but most other OLE objects seem to allow either and simply
call the default method themselves if they can't deal with an object.

I don't want to dive into indexed properties here, as it does not apply to
your situation.  The only thing you need to understand about them though is
that there is no default syntax mapped that would accept an index:

    $obj->IndexedProperty($index) = $value;

because at the time indexed properties were implemented in Win32::OLE there
was no support for lvalue funtions in Perl.  And I'm not sure if this could
be implemented even today, as the whole lvalue attribute stuff needs to be
known at compile time.

Anyways, so you always have to use either SetProperty() or LetProperty()
to assign to indexed properties. The discussion above should already
have explained why there are two different functions for indexed
property assignment.

> Using oleview.exe (from the ResKit) and the ITypeLib Viewer, I've
> extracted the following info:
> 
>           \,,,/
>           (o o)
> ------oOOo-(_)-oOOo------
> (1) interface IXMLDOMDocument, async property:
> [id(0x0000003d), propput, helpstring("flag for asynchronous download")]
> HRESULT async([in] VARIANT_BOOL isAsync);
> 
> (2) interface IXSLProcessor, input property:
> [id(0x00000002), propput, helpstring("XML input tree to transform")]
> HRESULT input([in] VARIANT pVar);
> -------------------------
> 
> Consider the following in Perl:
> 
>   $dom->{async} = 1;                        # correct
>   $xslProc->{input} = $xmlDoc;              # error
>   $xslProc->LetProperty(input => $xmlDoc);  # correct
> 
> Is there anything in the type viewer information telling me which syntax
> to use in each instance?

The "propput" keyword tells you that you should use LetProperty() in both
instances.  It just looks like "async" implements "propputref" as well
and does the right thing for you anyways.

I would not bother with this typelib stuff, just always use "by reference"
assignments everywhere, and only when it fails investigate if you are
running into a limitation of that objects implementation and have to use
"by value" assignment explicitly.

Cheers,
-Jan

_______________________________________________
ActivePerl mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs

Reply via email to