Following the case of the ambiguous property reference, Edi Weitz
reanimated the RDNZL repository on common-lisp.net, and I've commited
to it some fixes related to that issue, also making interop with COM a
bit nicer.
The repository is at svn://common-lisp.net/project/rdnzl/svn .
The changes since the current release are
1. bugfixes for CAST,
2. An improvement to PROPERTY, resolving ambiguous property
references by returning the value of the property defined in the most
specific class, and
3. Extensions to PROPERTY and INVOKE so as to better handle COM
objects with unknown type.
Changes one and three were found by testing the Excel example after
implementing change 2 and is mostly about an interesting feature of
.Net interop where several basic methods in .Net reflection completely
fail to work with COM objects - such as IsAssignable, GetProperty and
GetMethod. This bites when an application returns a COM object without
any interface information, done by for example Excel and others.
Now, CAST had a bug in the testing of whether or not a cast was legal
which hid this problem in the original Excel example; upon fixing this
bug CAST had to be extended to explicitly handle COM objects using
Marshal::GetComInterfaceForObject. The result should be that any COM
object should be castable to any interface it supports.
Even so, using PROPERTY on a COM object wouldn't neccessarily work, as
forexample shown by the call in examples/excel.lisp:
(cast [get_Item worksheets 1] "Worksheet")
This thanks to GetProperty not being supported. According to random
people on the internet, the way to get a property from a COM object
using reflection, was to use InvokeMember and thus get the property
using the IDispatch interface. I implemented this for properties and
methods for 'unknown type' COM objects, and it actually works, except
for the fact that since there is no way to get a PropertyInfo or
MethodInfo using this, the type of the return-value will be uknown and
thus probably a new __ComObject sans interface. But of course if all
one needs to do is to use properties and call methods on the object,
the interface or 'actual type' isn't actually neccessary. Thus, the
example quoted from in excel.lisp can be reduced to:
(defun get-excel-range (file-name range)
(let* ((app (new "ApplicationClass"))
(workbooks [%Workbooks app])
(workbook [Open workbooks file-name
+missing+ nil +missing+
+missing+ +missing+ +missing+
+missing+ +missing+ +missing+
+missing+ +missing+ +missing+
+missing+ +missing+])
(worksheets [%Worksheets workbook])
(sheet [%Item worksheets 1])
(range [%Range sheet range +missing+]))
(prog1 (cast [%Value2 [%Cells range]] "System.Array")
[Quit app])))
- eliminating two casts and two 'direct' call to the get_-methods
implementing a property.
As for the ambigous properties this is handled by a straightforward
search from most specific class upwards whenever the issue occurs,
thus making RDNZL work like common sense and other systems like C#. To
access a specific property given two of the same name, CASTing the
object to the class defining the property in which you are interested
works, like in C#.
I think this would probably be worth testing for any users of COM
Interop - it should remove a few sources of annoyance. Any comments or
bugreports would be welcome.
Iver