Author: ikvello Date: Fri May 2 10:02:14 2008 New Revision: 10
Modified: trunk/rdnzl-cpp/RDNZL/InvocationResult.cpp Log: CAST: Test of IsAssignale fixed, support for __ComObjects added, and better error-reporting for illegal casts. Also, test of SVN commits.
Modified: trunk/rdnzl-cpp/RDNZL/InvocationResult.cpp ============================================================================== --- trunk/rdnzl-cpp/RDNZL/InvocationResult.cpp (original) +++ trunk/rdnzl-cpp/RDNZL/InvocationResult.cpp Fri May 2 10:02:14 2008 @@ -73,17 +73,53 @@ void *setDotNetContainerType(Type ^newType, void *ptr) { try { DotNetContainer *container = static_cast<DotNetContainer *>(ptr); - Type ^oldType = container->getContainerType(); - - if (oldType->IsAssignableFrom(newType)) { - container->setContainerType(newType); - } else { - Object ^newObject = Convert::ChangeType(container->getContainerObject(), newType); - container->setContainerObject(newObject); + + // IOK 2008-04-25 we need the 'true' type of the object, + // not the 'nominal' type stored in the container, because for instance + // Excel will return an Array as an Object in certain situations. + // Type ^oldType = container->getContainerType(); + Object ^object = container->getContainerObject(); + Type ^oldType = object->GetType(); + + // IOK 2008-04-25 The normal case - assigning to the new type is legal. + if (newType->IsAssignableFrom(oldType)) { container->setContainerType(newType); + return new InvocationResult(); + } + + // When the object is actually a System.__ComObject, we can't use + // IsAssignable and must use QueryInterface through interop services. + // This happens for instance for certain objects returned from Office + // Interop. IOK 2008-04-25 + if (Marshal::IsComObject(object) && newType->IsInterface) { + // IOK 2007-05-02 Might want to wrap this in a try{}, and + // save the exception for later just in case we could have + // won using IConvert here. + System::IntPtr returnvalue = Marshal::GetComInterfaceForObject(object,newType); + bool success = (returnvalue != System::IntPtr::Zero); + if (success) { + Marshal::Release(returnvalue); + container->setContainerType(newType); + return new InvocationResult(); + } } - // return void result - return new InvocationResult(); + + // Not directly assignable, and not a __ComObject. IConvertible objects + // needs to be ChangeType'd then.. + if (nullptr != oldType->GetInterface("System.IConvertible")) { + Object ^newObject = Convert::ChangeType(object, newType); + container->setContainerObject(newObject); + container->setContainerType(newType); + return new InvocationResult(); + } + + // Nothing worked, so return an exception + return new InvocationResult( + gcnew System::InvalidCastException( + "Invalid cast from '" + oldType->FullName + "' to '" + newType->FullName +"'"), true); + + + // This handles exceptions thrown by Marshall::GetComInterfaceForObject and Convert::ChangeType. } catch (Exception ^e) { return new InvocationResult(e, true); }