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);