Author: ikvello Date: Fri May 9 10:53:29 2008 New Revision: 12
Modified: trunk/rdnzl-cpp/RDNZL/InvokeMember.cpp trunk/rdnzl-cpp/RDNZL/Property.cpp Log: Added support for accessing properties and methods of ComObjects with unknown interface (except for IDispatch)
Modified: trunk/rdnzl-cpp/RDNZL/InvokeMember.cpp ============================================================================== --- trunk/rdnzl-cpp/RDNZL/InvokeMember.cpp (original) +++ trunk/rdnzl-cpp/RDNZL/InvokeMember.cpp Fri May 9 10:53:29 2008 @@ -93,8 +93,21 @@ }
MethodInfo ^mi = findMethod(t, methodName, realTypes, bindingAttr); - if (mi == nullptr) - throwMethodNotFoundError(t, methodName, realTypes, bindingAttr); + if (mi == nullptr) { + // IOK 2008-05-09 no methodinfo can mean two things: One, that there + // was no method, and second, that we are dealing with a __ComObject + // directly and not through an interface. These objects are sometimes + // returned by applications like Excel. We can then call the method + // using IDispatch via InvokeMember. But, the returned object will + // also then typically be __ComObject, since we have no MethodInfo + // object to inspect for the return-type. The user must explicitly cast to + // the approprate type. + if (!Marshal::IsComObject(o)) throwMethodNotFoundError(t, methodName, realTypes, bindingAttr); + String ^name = gcnew String(methodName); + Object ^newInstance = t->InvokeMember(name, BindingFlags::InvokeMethod, nullptr, o, realArgs); + if (nullptr == newInstance) return new InvocationResult(); + else return new InvocationResult(newInstance,newInstance->GetType()); + }
Object ^newInstance = mi->Invoke(o, realArgs);
Modified: trunk/rdnzl-cpp/RDNZL/Property.cpp ============================================================================== --- trunk/rdnzl-cpp/RDNZL/Property.cpp (original) +++ trunk/rdnzl-cpp/RDNZL/Property.cpp Fri May 9 10:53:29 2008 @@ -86,10 +86,21 @@
// find property by name, binding attributes and index signature, handling ambiguos property references // by returning the most specific. - PropertyInfo ^pi = GetPropertyDisambiguatingSearch(t,gcnew String(propertyName), bindingAttr,realTypes); + String ^propname = gcnew String(propertyName); + PropertyInfo ^pi = GetPropertyDisambiguatingSearch(t, propname, bindingAttr,realTypes);
- if (pi == nullptr) - throwPropertyNotFoundError(t, propertyName, realTypes, bindingAttr); + if (pi == nullptr) { + // That the property isn't found either means it isn't there, or that our object was + // a __ComObject with no known interface; for which GetProperty does not work :(. + if (!Marshal::IsComObject(o)) throwPropertyNotFoundError(t, propertyName, realTypes, bindingAttr); + // Oh bother. We have a plain__ComObject, so we have to use InvokeMember, which will return + // another __ComObject with no extra type information - the user must explicitly CAST this + // to something useful. IOK 2008-05-08 + // Won't pass the ParameterModifier and namedParameters arguments to InvokeMember, + // it's not supported upstream and also not neccessary I think. IOK 2008-05-08 + Object ^prop = t->InvokeMember(propname, BindingFlags::GetProperty, nullptr, o, realArgs); + return new InvocationResult(prop, prop->GetType()); + }
return new InvocationResult(pi->GetValue(o, realArgs), pi->PropertyType); } catch (TargetInvocationException ^e) { @@ -138,10 +149,23 @@ }
// find property by name, binding attributes and index signature - PropertyInfo ^pi = GetPropertyDisambiguatingSearch(t,gcnew String(propertyName), bindingAttr,realTypes); + String ^propname = gcnew String(propertyName); + PropertyInfo ^pi = GetPropertyDisambiguatingSearch(t,propname, bindingAttr,realTypes);
- if (pi == nullptr) - throwPropertyNotFoundError(t, propertyName, realTypes, bindingAttr); + if (pi == nullptr) { + // That the property isn't found either means it isn't there, or that our object was + // a __ComObject with no known interface; for which GetProperty does not work :(. + if (!Marshal::IsComObject(o)) throwPropertyNotFoundError(t, propertyName, realTypes, bindingAttr); + // See comments for getPropertyValue. The call below is the same, except that BindingFlags + // are SetProperty, and that the args array needs to have the new values as the + // *last* element of the arguments. + Object ^newValue = static_cast<DotNetContainer *>(args[0])->getContainerObject(); + Array::Resize(realArgs,nargs); + realArgs->SetValue(newValue,(nargs -1)); + + Object ^prop = t->InvokeMember(propname, BindingFlags::SetProperty, nullptr, o, realArgs); + return new InvocationResult(); + }
// note that the new value is the first element of args pi->SetValue(o, static_cast<DotNetContainer *>(args[0])->getContainerObject(), realArgs);