1 //-----------------------------------------------------------------------------
4 // Category : SDK Core Interfaces
5 // Filename : pluginterfaces/base/funknown.h
6 // Created by : Steinberg, 01/2004
7 // Description : Basic Interface
9 //-----------------------------------------------------------------------------
10 // This file is part of a Steinberg SDK. It is subject to the license terms
11 // in the LICENSE file found in the top-level directory of this distribution
12 // and at www.steinberg.net/sdklicenses.
13 // No part of the SDK, including this file, may be copied, modified, propagated,
14 // or distributed except according to the terms contained in the LICENSE file.
15 //-----------------------------------------------------------------------------
19 #include "pluginterfaces/base/fplatform.h"
20 #include "pluginterfaces/base/ftypes.h"
21 #include "pluginterfaces/base/smartpointer.h"
24 #if SMTG_CPP11_STDLIBSUPPORT
25 #include <type_traits>
28 //------------------------------------------------------------------------
29 /*! \defgroup pluginBase Basic Interfaces
32 //------------------------------------------------------------------------
33 // Unique Identifier macros
34 //------------------------------------------------------------------------
37 #define INLINE_UID(l1, l2, l3, l4) \
39 (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x000000FF) ), (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x0000FF00) >> 8), \
40 (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x00FF0000) >> 16), (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0xFF000000) >> 24), \
41 (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x00FF0000) >> 16), (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0xFF000000) >> 24), \
42 (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x000000FF) ), (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x0000FF00) >> 8), \
43 (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x00FF0000) >> 16), \
44 (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x000000FF) ), \
45 (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x00FF0000) >> 16), \
46 (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x000000FF) ) \
49 #define INLINE_UID(l1, l2, l3, l4) \
51 (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x00FF0000) >> 16), \
52 (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l1) & 0x000000FF) ), \
53 (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x00FF0000) >> 16), \
54 (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l2) & 0x000000FF) ), \
55 (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x00FF0000) >> 16), \
56 (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l3) & 0x000000FF) ), \
57 (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0xFF000000) >> 24), (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x00FF0000) >> 16), \
58 (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x0000FF00) >> 8), (::Steinberg::int8)(((::Steinberg::uint32)(l4) & 0x000000FF) ) \
62 //------------------------------------------------------------------------
63 #define DECLARE_UID(name, l1, l2, l3, l4) ::Steinberg::TUID name = INLINE_UID (l1, l2, l3, l4);
65 //------------------------------------------------------------------------
66 #define EXTERN_UID(name) extern const ::Steinberg::TUID name;
69 #define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \
70 static const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4); \
72 const ::Steinberg::FUID ClassName::iid (ClassName##_iid);
74 #define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \
75 static const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4);
78 #define DEF_CLASS_IID(ClassName) const ::Steinberg::FUID ClassName::iid (ClassName##_iid);
80 #define INLINE_UID_OF(ClassName) ClassName##_iid
82 #define INLINE_UID_FROM_FUID(x) \
83 INLINE_UID (x.getLong1 (), x.getLong2 (), x.getLong3 (), x.getLong4 ())
85 //------------------------------------------------------------------------
86 // FUnknown implementation macros
87 //------------------------------------------------------------------------
89 #define DECLARE_FUNKNOWN_METHODS \
91 virtual ::Steinberg::tresult PLUGIN_API queryInterface (const ::Steinberg::TUID _iid, void** obj) SMTG_OVERRIDE; \
92 virtual ::Steinberg::uint32 PLUGIN_API addRef () SMTG_OVERRIDE; \
93 virtual ::Steinberg::uint32 PLUGIN_API release () SMTG_OVERRIDE; \
95 ::Steinberg::int32 __funknownRefCount; \
98 //------------------------------------------------------------------------
100 #define DELEGATE_REFCOUNT(ClassName) \
102 virtual ::Steinberg::uint32 PLUGIN_API addRef () SMTG_OVERRIDE { return ClassName::addRef (); } \
103 virtual ::Steinberg::uint32 PLUGIN_API release () SMTG_OVERRIDE { return ClassName::release (); }
105 //------------------------------------------------------------------------
106 #define IMPLEMENT_REFCOUNT(ClassName) \
107 ::Steinberg::uint32 PLUGIN_API ClassName::addRef () \
109 return ::Steinberg::FUnknownPrivate::atomicAdd (__funknownRefCount, 1); \
111 ::Steinberg::uint32 PLUGIN_API ClassName::release () \
113 if (::Steinberg::FUnknownPrivate::atomicAdd (__funknownRefCount, -1) == 0) \
118 return __funknownRefCount; \
121 //------------------------------------------------------------------------
122 #define FUNKNOWN_CTOR { __funknownRefCount = 1; }
123 #if SMTG_FUNKNOWN_DTOR_ASSERT
125 #define FUNKNOWN_DTOR { assert (__funknownRefCount == 0); }
127 #define FUNKNOWN_DTOR
130 //------------------------------------------------------------------------
131 #define QUERY_INTERFACE(iid, obj, InterfaceIID, InterfaceName) \
132 if (::Steinberg::FUnknownPrivate::iidEqual (iid, InterfaceIID)) \
135 *obj = static_cast< InterfaceName* >(this); \
136 return ::Steinberg::kResultOk; \
139 //------------------------------------------------------------------------
140 #define IMPLEMENT_QUERYINTERFACE(ClassName, InterfaceName, ClassIID) \
141 ::Steinberg::tresult PLUGIN_API ClassName::queryInterface (const ::Steinberg::TUID _iid, void** obj)\
143 QUERY_INTERFACE (_iid, obj, ::Steinberg::FUnknown::iid, InterfaceName) \
144 QUERY_INTERFACE (_iid, obj, ClassIID, InterfaceName) \
146 return ::Steinberg::kNoInterface; \
149 //------------------------------------------------------------------------
150 #define IMPLEMENT_FUNKNOWN_METHODS(ClassName,InterfaceName,ClassIID) \
151 IMPLEMENT_REFCOUNT (ClassName) \
152 IMPLEMENT_QUERYINTERFACE (ClassName, InterfaceName, ClassIID)
154 //------------------------------------------------------------------------
156 //------------------------------------------------------------------------
158 namespace Steinberg
{
160 //------------------------------------------------------------------------
165 kNoInterface
= static_cast<tresult
>(0x80004002L
), // E_NOINTERFACE
166 kResultOk
= static_cast<tresult
>(0x00000000L
), // S_OK
167 kResultTrue
= kResultOk
,
168 kResultFalse
= static_cast<tresult
>(0x00000001L
), // S_FALSE
169 kInvalidArgument
= static_cast<tresult
>(0x80070057L
), // E_INVALIDARG
170 kNotImplemented
= static_cast<tresult
>(0x80004001L
), // E_NOTIMPL
171 kInternalError
= static_cast<tresult
>(0x80004005L
), // E_FAIL
172 kNotInitialized
= static_cast<tresult
>(0x8000FFFFL
), // E_UNEXPECTED
173 kOutOfMemory
= static_cast<tresult
>(0x8007000EL
) // E_OUTOFMEMORY
178 kNoInterface
= static_cast<tresult
>(0x80000004L
), // E_NOINTERFACE
179 kResultOk
= static_cast<tresult
>(0x00000000L
), // S_OK
180 kResultTrue
= kResultOk
,
181 kResultFalse
= static_cast<tresult
>(0x00000001L
), // S_FALSE
182 kInvalidArgument
= static_cast<tresult
>(0x80000003L
), // E_INVALIDARG
183 kNotImplemented
= static_cast<tresult
>(0x80000001L
), // E_NOTIMPL
184 kInternalError
= static_cast<tresult
>(0x80000008L
), // E_FAIL
185 kNotInitialized
= static_cast<tresult
>(0x8000FFFFL
), // E_UNEXPECTED
186 kOutOfMemory
= static_cast<tresult
>(0x80000002L
) // E_OUTOFMEMORY
194 kResultTrue
= kResultOk
,
204 //------------------------------------------------------------------------
205 typedef int64 LARGE_INT
; // obsolete
207 //------------------------------------------------------------------------
208 // FUID class declaration
209 //------------------------------------------------------------------------
210 typedef int8 TUID
[16]; ///< plain UID type
212 //------------------------------------------------------------------------
213 /* FUnknown private */
214 namespace FUnknownPrivate
{
215 SMTG_ALWAYS_INLINE
bool iidEqual (const void* iid1
, const void* iid2
)
217 const uint64
* p1
= reinterpret_cast<const uint64
*> (iid1
);
218 const uint64
* p2
= reinterpret_cast<const uint64
*> (iid2
);
219 return p1
[0] == p2
[0] && p1
[1] == p2
[1];
222 int32 PLUGIN_API
atomicAdd (int32
& value
, int32 amount
);
225 //------------------------------------------------------------------------
226 /** Handling 16 Byte Globally Unique Identifiers.
229 Each interface declares its identifier as static member inside the interface
230 namespace (e.g. FUnknown::iid).
235 //------------------------------------------------------------------------
237 FUID (uint32 l1
, uint32 l2
, uint32 l3
, uint32 l4
);
241 #if SMTG_CPP11_STDLIBSUPPORT
243 FUID
& operator= (FUID
&& other
);
246 /** Generates a new Unique Identifier (UID).
247 Will return true for success. If the return value is false, either no
248 UID is generated or the UID is not guaranteed to be unique worldwide. */
251 /** Checks if the UID data is valid.
252 The default constructor initializes the memory with zeros. */
253 bool isValid () const;
255 FUID
& operator = (const FUID
& f
);
256 bool operator == (const FUID
& f
) const { return ::Steinberg::FUnknownPrivate::iidEqual (data
, f
.data
); }
257 bool operator < (const FUID
& f
) const { return memcmp (data
, f
.data
, sizeof (TUID
)) < 0; }
258 bool operator != (const FUID
& f
) const { return !::Steinberg::FUnknownPrivate::iidEqual (data
, f
.data
); }
260 uint32
getLong1 () const;
261 uint32
getLong2 () const;
262 uint32
getLong3 () const;
263 uint32
getLong4 () const;
265 void from4Int (uint32 d1
, uint32 d2
, uint32 d3
, uint32 d4
);
266 void to4Int (uint32
& d1
, uint32
& d2
, uint32
& d3
, uint32
& d4
) const;
268 typedef char8 String
[33];
270 /** Converts UID to a string.
271 The string will be 32 characters long, representing the hexadecimal values
272 of each data byte (e.g. "9127BE30160E4BB69966670AA6087880").
276 char8[33] strUID = {0};
279 uid.toString (strUID);
282 void toString (char8
* string
) const;
284 /** Sets the UID data from a string.
285 The string has to be 32 characters long, where each character-pair is
286 the ASCII-encoded hexadecimal value of the corresponding data byte. */
287 bool fromString (const char8
* string
);
289 /** Converts UID to a string in Microsoft(R) OLE format.
290 (e.g. "{c200e360-38c5-11ce-ae62-08002b2b79ef}") */
291 void toRegistryString (char8
* string
) const;
293 /** Sets the UID data from a string in Microsoft(R) OLE format. */
294 bool fromRegistryString (const char8
* string
);
298 kINLINE_UID
, ///< "INLINE_UID (0x00000000, 0x00000000, 0x00000000, 0x00000000)"
299 kDECLARE_UID
, ///< "DECLARE_UID (0x00000000, 0x00000000, 0x00000000, 0x00000000)"
300 kFUID
, ///< "FUID (0x00000000, 0x00000000, 0x00000000, 0x00000000)"
301 kCLASS_UID
///< "DECLARE_CLASS_IID (Interface, 0x00000000, 0x00000000, 0x00000000, 0x00000000)"
303 /** Prints the UID to a string (or debug output if string is NULL).
304 \param string is the output string if not NULL.
305 \param style can be chosen from the FUID::UIDPrintStyle enumeration. */
306 void print (char8
* string
= nullptr, int32 style
= kINLINE_UID
) const;
309 inline explicit FUID (const int8 (&uid
)[N
])
311 #if SMTG_CPP11_STDLIBSUPPORT
312 static_assert (N
== sizeof (TUID
), "only TUID allowed");
314 memcpy (data
, uid
, sizeof (TUID
));
316 inline void toTUID (TUID result
) const { memcpy (result
, data
, sizeof (TUID
)); }
317 inline operator const TUID
& () const { return data
; }
318 inline const TUID
& toTUID () const { return data
; }
320 static FUID
fromTUID (const TUID uid
)
324 memcpy (res
.data
, uid
, sizeof (TUID
));
328 //------------------------------------------------------------------------
333 #if SMTG_CPP11_STDLIBSUPPORT
334 template <typename T
>
335 inline bool operator== (const FUID
& f1
, T f2
)
338 std::is_same
<typename
std::remove_cv
<T
>::type
, FUID
>::value
,
339 "Do not compare a FUID with a TUID directly. Either convert the TUID to a FUID and compare them or use FUnknownPrivate::iidEqual");
340 return f1
.operator== (f2
);
344 //------------------------------------------------------------------------
346 //------------------------------------------------------------------------
347 /** The basic interface of all interfaces.
350 - The FUnknown::queryInterface method is used to retrieve pointers to other
351 interfaces of the object.
352 - FUnknown::addRef and FUnknown::release manage the lifetime of the object.
353 If no more references exist, the object is destroyed in memory.
355 Interfaces are identified by 16 byte Globally Unique Identifiers.
356 The SDK provides a class called FUID for this purpose.
364 //------------------------------------------------------------------------
365 /** Query for a pointer to the specified interface.
366 Returns kResultOk on success or kNoInterface if the object does not implement the interface.
367 The object has to call addRef when returning an interface.
368 \param _iid : (in) 16 Byte interface identifier (-> FUID)
369 \param obj : (out) On return, *obj points to the requested interface */
370 virtual tresult PLUGIN_API
queryInterface (const TUID _iid
, void** obj
) = 0;
372 /** Adds a reference and returns the new reference count.
374 The initial reference count after creating an object is 1. */
375 virtual uint32 PLUGIN_API
addRef () = 0;
377 /** Releases a reference and returns the new reference count.
378 If the reference count reaches zero, the object will be destroyed in memory. */
379 virtual uint32 PLUGIN_API
release () = 0;
381 //------------------------------------------------------------------------
382 static const FUID iid
;
383 //------------------------------------------------------------------------
387 DECLARE_CLASS_IID (FUnknown
, 0x00000000, 0x00000000, 0xC0000000, 0x00000046)
389 //------------------------------------------------------------------------
391 //------------------------------------------------------------------------
392 /** FUnknownPtr - automatic interface conversion and smart pointer in one.
393 This template class can be used for interface conversion like this:
395 IPtr<IPath> path = owned (FHostCreate (IPath, hostClasses));
396 FUnknownPtr<IPath2> path2 (path); // does a query interface for IPath2
402 class FUnknownPtr
: public IPtr
<I
>
405 //------------------------------------------------------------------------
406 inline FUnknownPtr (FUnknown
* unknown
); // query interface
407 inline FUnknownPtr (const FUnknownPtr
& p
) : IPtr
<I
> (p
) {}
408 inline FUnknownPtr () {}
410 inline FUnknownPtr
& operator= (const FUnknownPtr
& p
)
412 IPtr
<I
>::operator= (p
);
415 inline I
* operator= (FUnknown
* unknown
);
416 inline I
* getInterface () { return this->ptr
; }
418 #if SMTG_CPP11_STDLIBSUPPORT
419 inline FUnknownPtr (FUnknownPtr
&& p
) SMTG_NOEXCEPT
: IPtr
<I
> (std::move (p
)) {}
420 inline FUnknownPtr
& operator= (FUnknownPtr
&& p
) SMTG_NOEXCEPT
422 IPtr
<I
>::operator= (std::move (p
));
428 #if SMTG_CPP11_STDLIBSUPPORT
430 //------------------------------------------------------------------------
431 namespace FUnknownPrivate
{
433 template <typename T
>
434 struct Void
: std::false_type
439 template <typename T
>
440 using VoidT
= typename Void
<T
>::Type
;
442 //------------------------------------------------------------------------
444 * This type trait detects if a class has an @c iid member variable. It is used to detect if
445 * the FUID and DECLARE_CLASS_IID method or the SKI::UID method is used.
447 template <typename T
, typename U
= void>
448 struct HasIIDType
: std::false_type
452 //------------------------------------------------------------------------
453 template <typename T
>
454 struct HasIIDType
<T
, FUnknownPrivate::VoidT
<typename
T::IID
>> : std::true_type
458 //------------------------------------------------------------------------
461 //------------------------------------------------------------------------
462 /** @return the TUID for a SKI interface which uses the SKI::UID method. */
463 template <typename T
,
464 typename
std::enable_if
<FUnknownPrivate::HasIIDType
<T
>::value
>::type
* = nullptr>
465 const TUID
& getTUID ()
467 return T::IID::toTUID ();
470 //------------------------------------------------------------------------
471 /** @return the TUID for a SKI interface which uses the FUID and DECLARE_CLASS_IID method. */
472 template <typename T
,
473 typename
std::enable_if
<!FUnknownPrivate::HasIIDType
<T
>::value
>::type
* = nullptr>
474 const TUID
& getTUID ()
476 return T::iid
.toTUID ();
479 #else // SMTG_CPP11_STDLIBSUPPORT
482 const TUID
& getTUID ()
484 return T::iid
.toTUID ();
487 #endif // SMTG_CPP11_STDLIBSUPPORT
489 //------------------------------------------------------------------------
491 inline FUnknownPtr
<I
>::FUnknownPtr (FUnknown
* unknown
)
493 if (unknown
&& unknown
->queryInterface (getTUID
<I
> (), (void**)&this->ptr
) != kResultOk
)
497 //------------------------------------------------------------------------
499 inline I
* FUnknownPtr
<I
>::operator= (FUnknown
* unknown
)
502 if (unknown
&& unknown
->queryInterface (getTUID
<I
> (), (void**)&newPtr
) == kResultOk
)
504 OPtr
<I
> rel (newPtr
);
505 return IPtr
<I
>::operator= (newPtr
);
508 return IPtr
<I
>::operator= (0);
511 //------------------------------------------------------------------------
512 // FReleaser (obsolete)
513 //------------------------------------------------------------------------
514 /** Release an interface using automatic object (obsolete).
515 This class is obsolete and is only kept for compatibility.
516 The replacement for FReleaser is OPtr.
518 Usage example with FReleaser:
522 IPath* path = pathCreateMethod ();
523 FReleaser releaser (path);
524 .... do something with path...
525 .... path not used anymore, releaser will destroy it when leaving function scope
528 Usage example with OPtr:
532 OPtr<IPath> path = pathCreateMethod ();
533 .... do something with path...
534 .... path not used anymore, OPtr will destroy it when leaving function scope
540 FReleaser (FUnknown
* u
) : u (u
) {}
549 //------------------------------------------------------------------------
550 } // namespace Steinberg