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