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