1 //-----------------------------------------------------------------------------
2 // Project : SDK Core
3 //
4 // Category : SDK Core Interfaces
5 // Filename : pluginterfaces/base/funknown.h
6 // Created by : Steinberg, 01/2004
7 // Description : Basic Interface
8 //
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 //-----------------------------------------------------------------------------
16
17 #pragma once
18
19 #include "pluginterfaces/base/fplatform.h"
20 #include "pluginterfaces/base/ftypes.h"
21 #include "pluginterfaces/base/smartpointer.h"
22 #include <string.h>
23
24 //------------------------------------------------------------------------
25 /*! \defgroup pluginBase Basic Interfaces
26 */
27 //------------------------------------------------------------------------
28
29 //------------------------------------------------------------------------
30 // Unique Identifier macros
31 //------------------------------------------------------------------------
32
33 #if COM_COMPATIBLE
34 #define INLINE_UID(l1, l2, l3, l4) \
35 { \
36 (::Steinberg::int8)((l1 & 0x000000FF) ), (::Steinberg::int8)((l1 & 0x0000FF00) >> 8), \
37 (::Steinberg::int8)((l1 & 0x00FF0000) >> 16), (::Steinberg::int8)((l1 & 0xFF000000) >> 24), \
38 (::Steinberg::int8)((l2 & 0x00FF0000) >> 16), (::Steinberg::int8)((l2 & 0xFF000000) >> 24), \
39 (::Steinberg::int8)((l2 & 0x000000FF) ), (::Steinberg::int8)((l2 & 0x0000FF00) >> 8), \
40 (::Steinberg::int8)((l3 & 0xFF000000) >> 24), (::Steinberg::int8)((l3 & 0x00FF0000) >> 16), \
41 (::Steinberg::int8)((l3 & 0x0000FF00) >> 8), (::Steinberg::int8)((l3 & 0x000000FF) ), \
42 (::Steinberg::int8)((l4 & 0xFF000000) >> 24), (::Steinberg::int8)((l4 & 0x00FF0000) >> 16), \
43 (::Steinberg::int8)((l4 & 0x0000FF00) >> 8), (::Steinberg::int8)((l4 & 0x000000FF) ) \
44 }
45 #else
46 #define INLINE_UID(l1, l2, l3, l4) \
47 { \
48 (::Steinberg::int8)((l1 & 0xFF000000) >> 24), (::Steinberg::int8)((l1 & 0x00FF0000) >> 16), \
49 (::Steinberg::int8)((l1 & 0x0000FF00) >> 8), (::Steinberg::int8)((l1 & 0x000000FF) ), \
50 (::Steinberg::int8)((l2 & 0xFF000000) >> 24), (::Steinberg::int8)((l2 & 0x00FF0000) >> 16), \
51 (::Steinberg::int8)((l2 & 0x0000FF00) >> 8), (::Steinberg::int8)((l2 & 0x000000FF) ), \
52 (::Steinberg::int8)((l3 & 0xFF000000) >> 24), (::Steinberg::int8)((l3 & 0x00FF0000) >> 16), \
53 (::Steinberg::int8)((l3 & 0x0000FF00) >> 8), (::Steinberg::int8)((l3 & 0x000000FF) ), \
54 (::Steinberg::int8)((l4 & 0xFF000000) >> 24), (::Steinberg::int8)((l4 & 0x00FF0000) >> 16), \
55 (::Steinberg::int8)((l4 & 0x0000FF00) >> 8), (::Steinberg::int8)((l4 & 0x000000FF) ) \
56 }
57 #endif
58
59 //------------------------------------------------------------------------
60 #define DECLARE_UID(name, l1, l2, l3, l4) ::Steinberg::TUID name = INLINE_UID (l1, l2, l3, l4);
61
62 //------------------------------------------------------------------------
63 #define EXTERN_UID(name) extern const ::Steinberg::TUID name;
64
65 #ifdef INIT_CLASS_IID
66 #define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \
67 static const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4); \
68 \
69 const ::Steinberg::FUID ClassName::iid (ClassName##_iid);
70 #else
71 #define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \
72 static const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4);
73 #endif
74
75 #define DEF_CLASS_IID(ClassName) const ::Steinberg::FUID ClassName::iid (ClassName##_iid);
76
77 #define INLINE_UID_OF(ClassName) ClassName##_iid
78
79 #define INLINE_UID_FROM_FUID(x) \
80 INLINE_UID (x.getLong1 (), x.getLong2 (), x.getLong3 (), x.getLong4 ())
81
82 //------------------------------------------------------------------------
83 // FUnknown implementation macros
84 //------------------------------------------------------------------------
85
86 #define DECLARE_FUNKNOWN_METHODS \
87 public: \
88 virtual ::Steinberg::tresult PLUGIN_API queryInterface (const ::Steinberg::TUID _iid, void** obj) SMTG_OVERRIDE; \
89 virtual ::Steinberg::uint32 PLUGIN_API addRef () SMTG_OVERRIDE; \
90 virtual ::Steinberg::uint32 PLUGIN_API release () SMTG_OVERRIDE; \
91 protected : \
92 ::Steinberg::int32 __funknownRefCount; \
93 public:
94
95 //------------------------------------------------------------------------
96
97 #define DELEGATE_REFCOUNT(ClassName) \
98 public: \
99 virtual ::Steinberg::uint32 PLUGIN_API addRef () SMTG_OVERRIDE { return ClassName::addRef (); } \
100 virtual ::Steinberg::uint32 PLUGIN_API release () SMTG_OVERRIDE { return ClassName::release (); }
101
102 //------------------------------------------------------------------------
103 #define IMPLEMENT_REFCOUNT(ClassName) \
104 ::Steinberg::uint32 PLUGIN_API ClassName::addRef () \
105 { \
106 return ::Steinberg::FUnknownPrivate::atomicAdd (__funknownRefCount, 1); \
107 } \
108 ::Steinberg::uint32 PLUGIN_API ClassName::release () \
109 { \
110 if (::Steinberg::FUnknownPrivate::atomicAdd (__funknownRefCount, -1) == 0) \
111 { \
112 delete this; \
113 return 0; \
114 } \
115 return __funknownRefCount; \
116 }
117
118 //------------------------------------------------------------------------
119 #define FUNKNOWN_CTOR { __funknownRefCount = 1; }
120 #define FUNKNOWN_DTOR
121
122 //------------------------------------------------------------------------
123 #define QUERY_INTERFACE(iid, obj, InterfaceIID, InterfaceName) \
124 if (::Steinberg::FUnknownPrivate::iidEqual (iid, InterfaceIID)) \
125 { \
126 addRef (); \
127 *obj = static_cast< InterfaceName* >(this); \
128 return ::Steinberg::kResultOk; \
129 }
130
131 //------------------------------------------------------------------------
132 #define IMPLEMENT_QUERYINTERFACE(ClassName, InterfaceName, ClassIID) \
133 ::Steinberg::tresult PLUGIN_API ClassName::queryInterface (const ::Steinberg::TUID _iid, void** obj)\
134 { \
135 QUERY_INTERFACE (_iid, obj, ::Steinberg::FUnknown::iid, InterfaceName) \
136 QUERY_INTERFACE (_iid, obj, ClassIID, InterfaceName) \
137 *obj = nullptr; \
138 return ::Steinberg::kNoInterface; \
139 }
140
141 //------------------------------------------------------------------------
142 #define IMPLEMENT_FUNKNOWN_METHODS(ClassName,InterfaceName,ClassIID) \
143 IMPLEMENT_REFCOUNT (ClassName) \
144 IMPLEMENT_QUERYINTERFACE (ClassName, InterfaceName, ClassIID)
145
146 //------------------------------------------------------------------------
147 // Result Codes
148 //------------------------------------------------------------------------
149
150 namespace Steinberg {
151
152 //------------------------------------------------------------------------
153 #if COM_COMPATIBLE
154 #if SMTG_OS_WINDOWS
155 enum
156 {
157 kNoInterface = static_cast<tresult>(0x80004002L), // E_NOINTERFACE
158 kResultOk = static_cast<tresult>(0x00000000L), // S_OK
159 kResultTrue = kResultOk,
160 kResultFalse = static_cast<tresult>(0x00000001L), // S_FALSE
161 kInvalidArgument = static_cast<tresult>(0x80070057L), // E_INVALIDARG
162 kNotImplemented = static_cast<tresult>(0x80004001L), // E_NOTIMPL
163 kInternalError = static_cast<tresult>(0x80004005L), // E_FAIL
164 kNotInitialized = static_cast<tresult>(0x8000FFFFL), // E_UNEXPECTED
165 kOutOfMemory = static_cast<tresult>(0x8007000EL) // E_OUTOFMEMORY
166 };
167 #else
168 enum
169 {
170 kNoInterface = static_cast<tresult>(0x80000004L), // E_NOINTERFACE
171 kResultOk = static_cast<tresult>(0x00000000L), // S_OK
172 kResultTrue = kResultOk,
173 kResultFalse = static_cast<tresult>(0x00000001L), // S_FALSE
174 kInvalidArgument = static_cast<tresult>(0x80000003L), // E_INVALIDARG
175 kNotImplemented = static_cast<tresult>(0x80000001L), // E_NOTIMPL
176 kInternalError = static_cast<tresult>(0x80000008L), // E_FAIL
177 kNotInitialized = static_cast<tresult>(0x8000FFFFL), // E_UNEXPECTED
178 kOutOfMemory = static_cast<tresult>(0x80000002L) // E_OUTOFMEMORY
179 };
180 #endif
181 #else
182 enum
183 {
184 kNoInterface = -1,
185 kResultOk,
186 kResultTrue = kResultOk,
187 kResultFalse,
188 kInvalidArgument,
189 kNotImplemented,
190 kInternalError,
191 kNotInitialized,
192 kOutOfMemory
193 };
194 #endif
195
196 //------------------------------------------------------------------------
197 typedef int64 LARGE_INT; // obsolete
198
199 //------------------------------------------------------------------------
200 // FUID class declaration
201 //------------------------------------------------------------------------
202 typedef int8 TUID[16]; ///< plain UID type
203
204 //------------------------------------------------------------------------
205 /* FUnknown private */
206 namespace FUnknownPrivate {
iidEqual(const void * iid1,const void * iid2)207 SMTG_ALWAYS_INLINE bool iidEqual (const void* iid1, const void* iid2)
208 {
209 const uint64* p1 = reinterpret_cast<const uint64*> (iid1);
210 const uint64* p2 = reinterpret_cast<const uint64*> (iid2);
211 return p1[0] == p2[0] && p1[1] == p2[1];
212 }
213
214 int32 PLUGIN_API atomicAdd (int32& value, int32 amount);
215 }
216
217 //------------------------------------------------------------------------
218 /** Handling 16 Byte Globally Unique Identifiers.
219 \ingroup pluginBase
220
221 Each interface declares its identifier as static member inside the interface
222 namespace (e.g. FUnknown::iid).
223 */
224 //------------------------------------------------------------------------
225 class FUID
226 {
227 public:
228 //------------------------------------------------------------------------
229 FUID ();
230 FUID (uint32 l1, uint32 l2, uint32 l3, uint32 l4);
231 FUID (const FUID&);
~FUID()232 virtual ~FUID () {}
233
234 #if SMTG_CPP11_STDLIBSUPPORT
235 FUID (FUID&& other);
236 FUID& operator= (FUID&& other);
237 #endif
238
239 /** Generates a new Unique Identifier (UID).
240 Will return true for success. If the return value is false, either no
241 UID is generated or the UID is not guaranteed to be unique worldwide. */
242 bool generate ();
243
244 /** Checks if the UID data is valid.
245 The default constructor initializes the memory with zeros. */
246 bool isValid () const;
247
248 FUID& operator = (const FUID& f);
249 bool operator == (const FUID& f) const { return ::Steinberg::FUnknownPrivate::iidEqual (data, f.data); }
250 bool operator < (const FUID& f) const { return memcmp (data, f.data, sizeof (TUID)) < 0; }
251 bool operator != (const FUID& f) const { return !::Steinberg::FUnknownPrivate::iidEqual (data, f.data); }
252
253 uint32 getLong1 () const;
254 uint32 getLong2 () const;
255 uint32 getLong3 () const;
256 uint32 getLong4 () const;
257
258 void from4Int (uint32 d1, uint32 d2, uint32 d3, uint32 d4);
259 void to4Int (uint32& d1, uint32& d2, uint32& d3, uint32& d4) const;
260
261 typedef char8 String[64];
262
263 /** Converts UID to a string.
264 The string will be 32 characters long, representing the hexadecimal values
265 of each data byte (e.g. "9127BE30160E4BB69966670AA6087880").
266
267 Typical use-case is:
268 \code
269 char8[33] strUID = {0};
270 FUID uid;
271 if (uid.generate ())
272 uid.toString (strUID);
273 \endcode
274 */
275 void toString (char8* string) const;
276
277 /** Sets the UID data from a string.
278 The string has to be 32 characters long, where each character-pair is
279 the ASCII-encoded hexadecimal value of the corresponding data byte. */
280 bool fromString (const char8* string);
281
282 /** Converts UID to a string in Microsoft® OLE format.
283 (e.g. "{c200e360-38c5-11ce-ae62-08002b2b79ef}") */
284 void toRegistryString (char8* string) const;
285
286 /** Sets the UID data from a string in Microsoft® OLE format. */
287 bool fromRegistryString (const char8* string);
288
289 enum UIDPrintStyle
290 {
291 kINLINE_UID, ///< "INLINE_UID (0x00000000, 0x00000000, 0x00000000, 0x00000000)"
292 kDECLARE_UID, ///< "DECLARE_UID (0x00000000, 0x00000000, 0x00000000, 0x00000000)"
293 kFUID, ///< "FUID (0x00000000, 0x00000000, 0x00000000, 0x00000000)"
294 kCLASS_UID ///< "DECLARE_CLASS_IID (Interface, 0x00000000, 0x00000000, 0x00000000, 0x00000000)"
295 };
296 /** Prints the UID to a string (or debug output if string is NULL).
297 \param string is the output string if not NULL.
298 \param style can be chosen from the FUID::UIDPrintStyle enumeration. */
299 void print (char8* string = nullptr, int32 style = kINLINE_UID) const;
300
301 template <size_t N>
FUID(const int8 (& uid)[N])302 inline explicit FUID (const int8 (&uid)[N])
303 {
304 #if SMTG_CPP11_STDLIBSUPPORT
305 static_assert (N == sizeof (TUID), "only TUID allowed");
306 #endif
307 memcpy (data, uid, sizeof (TUID));
308 }
toTUID(TUID result)309 inline void toTUID (TUID result) const { memcpy (result, data, sizeof (TUID)); }
310 inline operator const TUID& () const { return data; }
toTUID()311 inline const TUID& toTUID () const { return data; }
312
fromTUID(const TUID uid)313 static FUID fromTUID (const TUID uid)
314 {
315 FUID res;
316 if (uid)
317 memcpy (res.data, uid, sizeof (TUID));
318 return res;
319 }
320
321 //------------------------------------------------------------------------
322 protected:
323 TUID data;
324 };
325
326 #if SMTG_CPP11_STDLIBSUPPORT
327 template <typename T>
328 inline bool operator== (const FUID& f1, T f2)
329 {
330 static_assert (
331 std::is_same<typename std::remove_cv<T>::type, FUID>::value,
332 "Do not compare a FUID with a TUID directly. Either convert the TUID to a FUID and compare them or use FUnknownPrivate::iidEqual");
333 return f1.operator== (f2);
334 }
335 #endif
336
337 //------------------------------------------------------------------------
338 // FUnknown
339 //------------------------------------------------------------------------
340 /** The basic interface of all interfaces.
341 \ingroup pluginBase
342
343 - The FUnknown::queryInterface method is used to retrieve pointers to other
344 interfaces of the object.
345 - FUnknown::addRef and FUnknown::release manage the lifetime of the object.
346 If no more references exist, the object is destroyed in memory.
347
348 Interfaces are identified by 16 byte Globally Unique Identifiers.
349 The SDK provides a class called FUID for this purpose.
350
351 \ref howtoClass */
352 //------------------------------------------------------------------------
353 class FUnknown
354 {
355 public:
356
357 //------------------------------------------------------------------------
358 /** Query for a pointer to the specified interface.
359 Returns kResultOk on success or kNoInterface if the object does not implement the interface.
360 The object has to call addRef when returning an interface.
361 \param _iid : (in) 16 Byte interface identifier (-> FUID)
362 \param obj : (out) On return, *obj points to the requested interface */
363 virtual tresult PLUGIN_API queryInterface (const TUID _iid, void** obj) = 0;
364
365 /** Adds a reference and return the new reference count.
366 \par Remarks:
367 The initial reference count after creating an object is 1. */
368 virtual uint32 PLUGIN_API addRef () = 0;
369
370 /** Releases a reference and return the new reference count.
371 If the reference count reaches zero, the object will be destroyed in memory. */
372 virtual uint32 PLUGIN_API release () = 0;
373
374 //------------------------------------------------------------------------
375 static const FUID iid;
376 //------------------------------------------------------------------------
377 };
378
379
380 DECLARE_CLASS_IID (FUnknown, 0x00000000, 0x00000000, 0xC0000000, 0x00000046)
381
382 //------------------------------------------------------------------------
383 // FUnknownPtr
384 //------------------------------------------------------------------------
385 /** FUnknownPtr - automatic interface conversion and smart pointer in one.
386 This template class can be used for interface conversion like this:
387 \code
388 IPtr<IPath> path = owned (FHostCreate (IPath, hostClasses));
389 FUnknownPtr<IPath2> path2 (path); // does a query interface for IPath2
390 if (path2)
391 ...
392 \endcode
393 */
394 //------------------------------------------------------------------------
395 template <class I>
396 class FUnknownPtr : public IPtr<I>
397 {
398 public:
399 //------------------------------------------------------------------------
400 inline FUnknownPtr (FUnknown* unknown); // query interface
FUnknownPtr(const FUnknownPtr & p)401 inline FUnknownPtr (const FUnknownPtr& p) : IPtr<I> (p) {}
FUnknownPtr()402 inline FUnknownPtr () {}
403
404 inline FUnknownPtr& operator= (const FUnknownPtr& p)
405 {
406 IPtr<I>::operator= (p);
407 return *this;
408 }
409 inline I* operator= (FUnknown* unknown);
getInterface()410 inline I* getInterface () { return this->ptr; }
411 };
412
413 //------------------------------------------------------------------------
414 template <class I>
FUnknownPtr(FUnknown * unknown)415 inline FUnknownPtr<I>::FUnknownPtr (FUnknown* unknown)
416 {
417 if (unknown && unknown->queryInterface (I::iid, (void**)&this->ptr) != kResultOk)
418 this->ptr = 0;
419 }
420
421 //------------------------------------------------------------------------
422 template <class I>
423 inline I* FUnknownPtr<I>::operator= (FUnknown* unknown)
424 {
425 I* newPtr = 0;
426 if (unknown && unknown->queryInterface (I::iid, (void**)&newPtr) == kResultOk)
427 {
428 OPtr<I> rel (newPtr);
429 return IPtr<I>::operator= (newPtr);
430 }
431
432 return IPtr<I>::operator= (0);
433 }
434
435 //------------------------------------------------------------------------
436 // FReleaser (obsolete)
437 //------------------------------------------------------------------------
438 /** Release an interface using automatic object (obsolete).
439 This class is obsolete and is only kept for compatibility.
440 The replacement for FReleaser is OPtr.
441
442 Usage example with FReleaser:
443 \code
444 void someFunction ()
445 {
446 IPath* path = pathCreateMethod ();
447 FReleaser releaser (path);
448 .... do something with path...
449 .... path not used anymore, releaser will destroy it when leaving function scope
450 }
451 \endcode
452 Usage example with OPtr:
453 \code
454 void someFunction ()
455 {
456 OPtr<IPath> path = pathCreateMethod ();
457 .... do something with path...
458 .... path not used anymore, OPtr will destroy it when leaving function scope
459 }
460 \endcode
461 */
462 //------------------------------------------------------------------------
463 struct FReleaser
464 {
FReleaserFReleaser465 FReleaser (FUnknown* u) : u (u) {}
~FReleaserFReleaser466 ~FReleaser ()
467 {
468 if (u)
469 u->release ();
470 }
471 FUnknown* u;
472 };
473
474 //------------------------------------------------------------------------
475 } // namespace Steinberg
476