summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--comphelper/source/misc/compbase.cxx181
-rw-r--r--include/comphelper/compbase.hxx23
2 files changed, 197 insertions, 7 deletions
diff --git a/comphelper/source/misc/compbase.cxx b/comphelper/source/misc/compbase.cxx
index 6e2019a255ae..ff3c4778b2ba 100644
--- a/comphelper/source/misc/compbase.cxx
+++ b/comphelper/source/misc/compbase.cxx
@@ -8,6 +8,8 @@
*/
#include <comphelper/compbase.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
namespace comphelper
{
@@ -45,6 +47,185 @@ void SAL_CALL WeakComponentImplHelperBase::removeEventListener(
maEventListeners.removeInterface(rxListener);
}
+css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType)
+{
+ css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
+ static_cast<css::lang::XComponent*>(this));
+ if (aReturn.hasValue())
+ return aReturn;
+ return OWeakObject::queryInterface(rType);
+}
+
+static void checkInterface(css::uno::Type const& rType)
+{
+ if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
+ {
+ OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!");
+ SAL_WARN("cppuhelper", msg);
+ throw css::uno::RuntimeException(msg);
+ }
+}
+
+static bool isXInterface(rtl_uString* pStr)
+{
+ return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface";
+}
+
+static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
+ typelib_TypeDescriptionReference const* pTDR2)
+{
+ return ((pTDR1 == pTDR2)
+ || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
+}
+
+static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
+{
+ cppu::type_entry* pEntries = cd->m_typeEntries;
+ if (!cd->m_storedTypeRefs) // not inited?
+ {
+ static std::mutex aMutex;
+ std::scoped_lock guard(aMutex);
+ if (!cd->m_storedTypeRefs) // not inited?
+ {
+ // get all types
+ for (sal_Int32 n = cd->m_nTypes; n--;)
+ {
+ cppu::type_entry* pEntry = &pEntries[n];
+ css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
+ OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
+ "### wrong helper init: expected interface!");
+ OSL_ENSURE(
+ !isXInterface(rType.getTypeLibType()->pTypeName),
+ "### want to implement XInterface: template argument is XInterface?!?!?!");
+ if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
+ {
+ OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!");
+ SAL_WARN("cppuhelper", msg);
+ throw css::uno::RuntimeException(msg);
+ }
+ // ref is statically held by getCppuType()
+ pEntry->m_type.typeRef = rType.getTypeLibType();
+ }
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ cd->m_storedTypeRefs = true;
+ }
+ }
+ else
+ {
+ OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+ }
+ return pEntries;
+}
+
+static void* makeInterface(sal_IntPtr nOffset, void* that)
+{
+ return (static_cast<char*>(that) + nOffset);
+}
+
+static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
+ typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
+{
+ // This code assumes that the vtables of a multiple-inheritance class (the
+ // offset amount by which to adjust the this pointer) follow one another in
+ // the object layout, and that they contain slots for the inherited classes
+ // in a specific order. In theory, that need not hold for any given
+ // platform; in practice, it seems to work well on all supported platforms:
+next:
+ for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
+ {
+ if (i > 0)
+ {
+ *offset += sizeof(void*);
+ }
+ typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
+ // ignore XInterface:
+ if (base->nBaseTypes > 0)
+ {
+ if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
+ demandedType))
+ {
+ return true;
+ }
+ // Profiling showed that it is important to speed up the common case
+ // of only one base:
+ if (type->nBaseTypes == 1)
+ {
+ type = base;
+ goto next;
+ }
+ if (recursivelyFindType(demandedType, base, offset))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
+ cppu::class_data* cd, void* that)
+{
+ cppu::type_entry* pEntries = getTypeEntries(cd);
+ sal_Int32 nTypes = cd->m_nTypes;
+ sal_Int32 n;
+
+ // try top interfaces without getting td
+ for (n = 0; n < nTypes; ++n)
+ {
+ if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
+ {
+ return makeInterface(pEntries[n].m_offset, that);
+ }
+ }
+ // query deep getting td
+ for (n = 0; n < nTypes; ++n)
+ {
+ typelib_TypeDescription* pTD = nullptr;
+ TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
+ if (pTD)
+ {
+ // exclude top (already tested) and bottom (XInterface) interface
+ OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
+ "### want to implement XInterface:"
+ " template argument is XInterface?!?!?!");
+ sal_IntPtr offset = pEntries[n].m_offset;
+ bool found = recursivelyFindType(
+ pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
+ TYPELIB_DANGER_RELEASE(pTD);
+ if (found)
+ {
+ return makeInterface(offset, that);
+ }
+ }
+ else
+ {
+ OUString msg("cannot get type description for type \""
+ + OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
+ SAL_WARN("cppuhelper", msg);
+ throw css::uno::RuntimeException(msg);
+ }
+ }
+ return nullptr;
+}
+
+css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
+ WeakComponentImplHelperBase* pBase)
+{
+ checkInterface(rType);
+ typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
+
+ // shortcut XInterface to WeakComponentImplHelperBase
+ if (!isXInterface(pTDR->pTypeName))
+ {
+ void* p = queryDeepNoXInterface(pTDR, cd, pBase);
+ if (p)
+ {
+ return css::uno::Any(&p, pTDR);
+ }
+ }
+ return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType);
+}
+
} // namespace comphelper
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/include/comphelper/compbase.hxx b/include/comphelper/compbase.hxx
index 5b7e1f7ba7a1..38380ede20d0 100644
--- a/include/comphelper/compbase.hxx
+++ b/include/comphelper/compbase.hxx
@@ -15,6 +15,7 @@
#include <comphelper/interfacecontainer4.hxx>
#include <cppuhelper/weak.hxx>
#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/implbase.hxx>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <mutex>
@@ -40,6 +41,8 @@ public:
virtual void SAL_CALL
removeEventListener(css::uno::Reference<css::lang::XEventListener> const& rxListener) override;
+ virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const& rType) override;
+
/**
Called by dispose for subclasses to do dispose() work.
The mutex is held when called, and subclasses can unlock() the guard if necessary.
@@ -80,13 +83,7 @@ public:
virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const& rType) override
{
- css::uno::Any aReturn = ::cppu::queryInterface(
- rType, static_cast<css::uno::XWeak*>(this),
- static_cast<css::lang::XComponent*>(static_cast<WeakComponentImplHelperBase*>(this)),
- static_cast<css::lang::XTypeProvider*>(this), static_cast<Ifc*>(this)...);
- if (aReturn.hasValue())
- return aReturn;
- return OWeakObject::queryInterface(rType);
+ return WeakComponentImplHelper_query(rType, class_data_get(), this);
}
// css::lang::XTypeProvider
@@ -102,8 +99,20 @@ public:
{
return css::uno::Sequence<sal_Int8>();
}
+
+private:
+ static cppu::class_data* class_data_get()
+ {
+ return cppu::detail::ImplClassData<WeakComponentImplHelper, Ifc...>{}();
+ }
};
+/** WeakComponentImplHelper
+*/
+COMPHELPER_DLLPUBLIC css::uno::Any
+WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
+ WeakComponentImplHelperBase* pBase);
+
} // namespace comphelper
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */