1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <comphelper/compbase.hxx>
11 #include <cppuhelper/queryinterface.hxx>
12 #include <sal/log.hxx>
13 #include <osl/diagnose.h>
17 WeakComponentImplHelperBase::~WeakComponentImplHelperBase() {}
19 // css::lang::XComponent
20 void SAL_CALL
WeakComponentImplHelperBase::dispose()
22 std::unique_lock
aGuard(m_aMutex
);
27 if (!aGuard
.owns_lock())
29 css::lang::EventObject
aEvt(static_cast<OWeakObject
*>(this));
30 maEventListeners
.disposeAndClear(aGuard
, aEvt
);
33 // This is only called from the destructor to do cleanup that
34 // might not have occurred
35 void WeakComponentImplHelperBase::disposeOnDestruct()
37 std::unique_lock
aGuard(m_aMutex
);
38 assert(m_refCount
== 0 && "only supposed to be called from the destructor");
42 // bump the ref-count so we don't accidentally do a double delete
43 // if something else increases and then decreases our ref-count
44 cppu::OWeakObject::acquire();
48 void WeakComponentImplHelperBase::disposing(std::unique_lock
<std::mutex
>&) {}
50 void SAL_CALL
WeakComponentImplHelperBase::addEventListener(
51 css::uno::Reference
<css::lang::XEventListener
> const& rxListener
)
53 std::unique_lock
aGuard(m_aMutex
);
56 maEventListeners
.addInterface(aGuard
, rxListener
);
59 void SAL_CALL
WeakComponentImplHelperBase::removeEventListener(
60 css::uno::Reference
<css::lang::XEventListener
> const& rxListener
)
62 std::unique_lock
aGuard(m_aMutex
);
63 maEventListeners
.removeInterface(aGuard
, rxListener
);
66 css::uno::Any SAL_CALL
WeakComponentImplHelperBase::queryInterface(css::uno::Type
const& rType
)
68 css::uno::Any aReturn
= ::cppu::queryInterface(rType
, static_cast<css::uno::XWeak
*>(this),
69 static_cast<css::lang::XComponent
*>(this));
70 if (aReturn
.hasValue())
72 return OWeakObject::queryInterface(rType
);
75 static void checkInterface(css::uno::Type
const& rType
)
77 if (css::uno::TypeClass_INTERFACE
!= rType
.getTypeClass())
79 OUString
msg("querying for interface \"" + rType
.getTypeName() + "\": no interface type!");
80 SAL_WARN("cppuhelper", msg
);
81 throw css::uno::RuntimeException(msg
);
85 static bool isXInterface(rtl_uString
* pStr
)
87 return OUString::unacquired(&pStr
) == "com.sun.star.uno.XInterface";
90 static bool td_equals(typelib_TypeDescriptionReference
const* pTDR1
,
91 typelib_TypeDescriptionReference
const* pTDR2
)
93 return ((pTDR1
== pTDR2
)
94 || OUString::unacquired(&pTDR1
->pTypeName
) == OUString::unacquired(&pTDR2
->pTypeName
));
97 static cppu::type_entry
* getTypeEntries(cppu::class_data
* cd
)
99 cppu::type_entry
* pEntries
= cd
->m_typeEntries
;
101 static std::mutex aMutex
;
102 std::scoped_lock
guard(aMutex
);
103 if (!cd
->m_storedTypeRefs
) // not inited?
106 for (sal_Int32 n
= cd
->m_nTypes
; n
--;)
108 cppu::type_entry
* pEntry
= &pEntries
[n
];
109 css::uno::Type
const& rType
= (*pEntry
->m_type
.getCppuType
)(nullptr);
110 OSL_ENSURE(rType
.getTypeClass() == css::uno::TypeClass_INTERFACE
,
111 "### wrong helper init: expected interface!");
113 !isXInterface(rType
.getTypeLibType()->pTypeName
),
114 "### want to implement XInterface: template argument is XInterface?!?!?!");
115 if (rType
.getTypeClass() != css::uno::TypeClass_INTERFACE
)
117 OUString
msg("type \"" + rType
.getTypeName() + "\" is no interface type!");
118 SAL_WARN("cppuhelper", msg
);
119 throw css::uno::RuntimeException(msg
);
121 // ref is statically held by getCppuType()
122 pEntry
->m_type
.typeRef
= rType
.getTypeLibType();
124 cd
->m_storedTypeRefs
= true;
130 static void* makeInterface(sal_IntPtr nOffset
, void* that
)
132 return (static_cast<char*>(that
) + nOffset
);
135 static bool recursivelyFindType(typelib_TypeDescriptionReference
const* demandedType
,
136 typelib_InterfaceTypeDescription
const* type
, sal_IntPtr
* offset
)
138 // This code assumes that the vtables of a multiple-inheritance class (the
139 // offset amount by which to adjust the this pointer) follow one another in
140 // the object layout, and that they contain slots for the inherited classes
141 // in a specific order. In theory, that need not hold for any given
142 // platform; in practice, it seems to work well on all supported platforms:
144 for (sal_Int32 i
= 0; i
< type
->nBaseTypes
; ++i
)
148 *offset
+= sizeof(void*);
150 typelib_InterfaceTypeDescription
const* base
= type
->ppBaseTypes
[i
];
151 // ignore XInterface:
152 if (base
->nBaseTypes
> 0)
154 if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference
const*>(base
),
159 // Profiling showed that it is important to speed up the common case
161 if (type
->nBaseTypes
== 1)
166 if (recursivelyFindType(demandedType
, base
, offset
))
175 static void* queryDeepNoXInterface(typelib_TypeDescriptionReference
const* pDemandedTDR
,
176 cppu::class_data
* cd
, void* that
)
178 cppu::type_entry
* pEntries
= getTypeEntries(cd
);
179 sal_Int32 nTypes
= cd
->m_nTypes
;
182 // try top interfaces without getting td
183 for (n
= 0; n
< nTypes
; ++n
)
185 if (td_equals(pEntries
[n
].m_type
.typeRef
, pDemandedTDR
))
187 return makeInterface(pEntries
[n
].m_offset
, that
);
190 // query deep getting td
191 for (n
= 0; n
< nTypes
; ++n
)
193 typelib_TypeDescription
* pTD
= nullptr;
194 TYPELIB_DANGER_GET(&pTD
, pEntries
[n
].m_type
.typeRef
);
197 // exclude top (already tested) and bottom (XInterface) interface
198 OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription
*>(pTD
)->nBaseTypes
> 0,
199 "### want to implement XInterface:"
200 " template argument is XInterface?!?!?!");
201 sal_IntPtr offset
= pEntries
[n
].m_offset
;
202 bool found
= recursivelyFindType(
203 pDemandedTDR
, reinterpret_cast<typelib_InterfaceTypeDescription
*>(pTD
), &offset
);
204 TYPELIB_DANGER_RELEASE(pTD
);
207 return makeInterface(offset
, that
);
212 OUString
msg("cannot get type description for type \""
213 + OUString::unacquired(&pEntries
[n
].m_type
.typeRef
->pTypeName
) + "\"!");
214 SAL_WARN("cppuhelper", msg
);
215 throw css::uno::RuntimeException(msg
);
221 css::uno::Any
WeakComponentImplHelper_query(css::uno::Type
const& rType
, cppu::class_data
* cd
,
222 WeakComponentImplHelperBase
* pBase
)
224 checkInterface(rType
);
225 typelib_TypeDescriptionReference
* pTDR
= rType
.getTypeLibType();
227 // shortcut XInterface to WeakComponentImplHelperBase
228 if (!isXInterface(pTDR
->pTypeName
))
230 void* p
= queryDeepNoXInterface(pTDR
, cd
, pBase
);
233 return css::uno::Any(&p
, pTDR
);
236 return pBase
->comphelper::WeakComponentImplHelperBase::queryInterface(rType
);
239 WeakImplHelperBase::~WeakImplHelperBase() {}
241 css::uno::Any SAL_CALL
WeakImplHelperBase::queryInterface(css::uno::Type
const& rType
)
243 css::uno::Any aReturn
= ::cppu::queryInterface(rType
, static_cast<css::uno::XWeak
*>(this));
244 if (aReturn
.hasValue())
246 return OWeakObject::queryInterface(rType
);
249 css::uno::Any
WeakImplHelper_query(css::uno::Type
const& rType
, cppu::class_data
* cd
,
250 WeakImplHelperBase
* pBase
)
252 checkInterface(rType
);
253 typelib_TypeDescriptionReference
* pTDR
= rType
.getTypeLibType();
255 // shortcut XInterface to WeakComponentImplHelperBase
256 if (!isXInterface(pTDR
->pTypeName
))
258 void* p
= queryDeepNoXInterface(pTDR
, cd
, pBase
);
261 return css::uno::Any(&p
, pTDR
);
264 return pBase
->comphelper::WeakImplHelperBase::queryInterface(rType
);
267 } // namespace comphelper
269 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */