summaryrefslogtreecommitdiffstats
path: root/ComLightLib/server
diff options
context:
space:
mode:
authorKonstantin <const@const.me>2023-01-16 14:52:43 +0100
committerKonstantin <const@const.me>2023-01-16 14:52:43 +0100
commit8c4603c73675958efc960fbd4bb599a2909d106a (patch)
tree714dc6fc9a1672d5fd7f89676b97e10959662abc /ComLightLib/server
parent990a8d0dbaefc996244097397259e92758b15cce (diff)
Source codes
Diffstat (limited to 'ComLightLib/server')
-rw-r--r--ComLightLib/server/Object.hpp139
-rw-r--r--ComLightLib/server/ObjectRoot.hpp51
-rw-r--r--ComLightLib/server/RefCounter.hpp38
-rw-r--r--ComLightLib/server/freeThreadedMarshaller.cpp17
-rw-r--r--ComLightLib/server/freeThreadedMarshaller.h29
-rw-r--r--ComLightLib/server/interfaceMap.h31
6 files changed, 305 insertions, 0 deletions
diff --git a/ComLightLib/server/Object.hpp b/ComLightLib/server/Object.hpp
new file mode 100644
index 0000000..d2e3257
--- /dev/null
+++ b/ComLightLib/server/Object.hpp
@@ -0,0 +1,139 @@
+#pragma once
+#include <type_traits>
+#include "../comLightClient.h"
+#include "../utils/typeTraits.hpp"
+#include "../Exception.hpp"
+
+namespace ComLight
+{
+ namespace details
+ {
+ GENERATE_HAS_MEMBER( implQueryInterface );
+ GENERATE_HAS_MEMBER( implAddRef );
+ GENERATE_HAS_MEMBER( implRelease );
+ }
+
+ // Outer class of objects, implements IUnknown methods, also the class factory. The type argument must be your class implementing your interfaces, inherited from ObjectRoot<I>
+ template<class T>
+ class Object : public T
+ {
+ public:
+ Object() = default;
+
+ template<typename ... Args>
+ Object( Args&& ... args ) : T{ std::forward<Args>( args )... } {};
+
+ inline virtual ~Object() override { }
+
+ // Implement IUnknown methods
+ HRESULT COMLIGHTCALL QueryInterface( REFIID riid, void** ppvObject ) override
+ {
+ static_assert( details::has_member_implQueryInterface<T>::value, "Your object class must inherit from ComLight::ObjectRoot" );
+
+ if( nullptr == ppvObject )
+ return E_POINTER;
+
+ if( T::implQueryInterface( riid, ppvObject ) )
+ return S_OK;
+ if( T::queryExtraInterfaces( riid, ppvObject ) )
+ return S_OK;
+
+ if( riid == IUnknown::iid() )
+ {
+ ComLight::IUnknown* unk = T::getUnknown();
+ unk->AddRef();
+ *ppvObject = unk;
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ uint32_t COMLIGHTCALL AddRef() override
+ {
+ static_assert( details::has_member_implAddRef<T>::value, "Your object class must inherit from ComLight::ObjectRoot" );
+ return T::implAddRef();
+ }
+
+ uint32_t COMLIGHTCALL Release() override
+ {
+ static_assert( details::has_member_implRelease<T>::value, "Your object class must inherit from ComLight::ObjectRoot" );
+ const uint32_t ret = T::implRelease();
+ if( 0 == ret )
+ {
+ T::FinalRelease();
+ delete this;
+ }
+ return ret;
+ }
+
+ // Create a new object on the heap, store in smart pointer
+ static inline HRESULT create( CComPtr<Object<T>>& result )
+ {
+ CComPtr<Object<T>> ptr;
+ try
+ {
+ ptr = new Object<T>(); // The RefCounter constructor creates it with ref.counter 0. But then CComPtr constructor calls AddRef so we have RC=1 after this line.
+
+ HRESULT hr = ptr->internalFinalConstruct();
+ if( FAILED( hr ) )
+ return hr;
+
+ hr = ptr->FinalConstruct();
+ if( FAILED( hr ) )
+ return hr;
+
+ ptr.swap( result );
+ return S_OK;
+ }
+ catch( const Exception& ex )
+ {
+ return ex.code();
+ }
+ }
+
+ // Create a new object on the heap, store in smart pointer
+ template<typename ... Args>
+ static inline HRESULT create( CComPtr<Object<T>>& result, Args&& ... args )
+ {
+ CComPtr<Object<T>> ptr;
+ try
+ {
+ ptr = new Object<T>( std::forward<Args>( args )... );
+
+ HRESULT hr = ptr->internalFinalConstruct();
+ if( FAILED( hr ) )
+ return hr;
+
+ hr = ptr->FinalConstruct();
+ if( FAILED( hr ) )
+ return hr;
+
+ ptr.swap( result );
+ return S_OK;
+ }
+ catch( const Exception& ex )
+ {
+ return ex.code();
+ }
+ catch( HRESULT hr )
+ {
+ return hr;
+ }
+ }
+
+ // Create a new object on the heap, return one of it's interfaces. The caller is assumed to take ownership of the new object.
+ template<class I>
+ static inline HRESULT create( I** pp )
+ {
+ if( pp == nullptr )
+ return E_POINTER;
+
+ static_assert( details::pointersAssignable<I, T>(), "Object::create can't cast object to the requested interface" );
+ CComPtr<Object<T>> ptr;
+ CHECK( create( ptr ) );
+ ptr.detach( pp );
+ return S_OK;
+ }
+ };
+} \ No newline at end of file
diff --git a/ComLightLib/server/ObjectRoot.hpp b/ComLightLib/server/ObjectRoot.hpp
new file mode 100644
index 0000000..1cc8f4d
--- /dev/null
+++ b/ComLightLib/server/ObjectRoot.hpp
@@ -0,0 +1,51 @@
+#pragma once
+#include "RefCounter.hpp"
+#include "../comLightCommon.h"
+#include "../utils/typeTraits.hpp"
+
+namespace ComLight
+{
+ // Base class of objects, implements reference counting, also a few lifetime methods.
+ // The template argument is the interface you want clients to get when they ask for IID_IUnknown. By convention, that pointer defines object's identity.
+ template<class I>
+ class ObjectRoot : public RefCounter, public I
+ {
+ protected:
+
+ inline HRESULT internalFinalConstruct()
+ {
+ return S_FALSE;
+ }
+
+ inline HRESULT FinalConstruct()
+ {
+ return S_FALSE;
+ }
+
+ inline void FinalRelease() { }
+
+ IUnknown* getUnknown()
+ {
+ static_assert( details::pointersAssignable<IUnknown, I>(), "The interface doesn't derive from IUnknown" );
+ return static_cast<I*>( this );
+ }
+
+ bool queryExtraInterfaces( REFIID riid, void **ppvObject ) const
+ {
+ return false;
+ }
+
+ // Implement query interface with 2 entries, IUnknown and I.
+ bool implQueryInterface( REFIID riid, void** ppvObject )
+ {
+ if( riid == I::iid() || riid == IUnknown::iid() )
+ {
+ I* const result = this;
+ result->AddRef();
+ *ppvObject = result;
+ return true;
+ }
+ return false;
+ }
+ };
+} \ No newline at end of file
diff --git a/ComLightLib/server/RefCounter.hpp b/ComLightLib/server/RefCounter.hpp
new file mode 100644
index 0000000..9698cc8
--- /dev/null
+++ b/ComLightLib/server/RefCounter.hpp
@@ -0,0 +1,38 @@
+#pragma once
+#include <atomic>
+#include <assert.h>
+#include <limits.h>
+
+namespace ComLight
+{
+ // Very base class of objects, implements reference counting.
+ class RefCounter
+ {
+ std::atomic_uint referenceCounter;
+
+ public:
+
+ RefCounter() : referenceCounter( 0 ) { }
+
+ inline virtual ~RefCounter() { }
+
+ RefCounter( const RefCounter &that ) = delete;
+ RefCounter( RefCounter &&that ) = delete;
+
+ protected:
+
+ uint32_t implAddRef()
+ {
+ return ++referenceCounter;
+ }
+
+ uint32_t implRelease()
+ {
+ // Might be a good idea to use locks, at least in debug builds. They're much slower than atomics, but with locks it's possible to detect when 2 threads call release at the same time, for object with counter = 1.
+ // It's a memory management bug, but it would be nice if debug builds would handle that case gracefully.
+ const uint32_t rc = --referenceCounter;
+ assert( rc != UINT_MAX );
+ return rc;
+ }
+ };
+} \ No newline at end of file
diff --git a/ComLightLib/server/freeThreadedMarshaller.cpp b/ComLightLib/server/freeThreadedMarshaller.cpp
new file mode 100644
index 0000000..fc1ea80
--- /dev/null
+++ b/ComLightLib/server/freeThreadedMarshaller.cpp
@@ -0,0 +1,17 @@
+#include "freeThreadedMarshaller.h"
+#ifdef _MSC_VER
+#include <combaseapi.h>
+
+HRESULT ComLight::details::createFreeThreadedMarshaller( IUnknown* pUnkOuter, IUnknown** ppUnkMarshal )
+{
+ return ::CoCreateFreeThreadedMarshaler( (LPUNKNOWN)pUnkOuter, (LPUNKNOWN *)ppUnkMarshal );
+}
+
+bool ComLight::details::queryMarshallerInterface( REFIID riid, void **ppvObject, IUnknown* marshaller )
+{
+ if( riid != IID_IMarshal || nullptr == marshaller )
+ return false;
+ const HRESULT hr = marshaller->QueryInterface( IID_IMarshal, ppvObject );
+ return SUCCEEDED( hr ) ? true : false;
+}
+#endif \ No newline at end of file
diff --git a/ComLightLib/server/freeThreadedMarshaller.h b/ComLightLib/server/freeThreadedMarshaller.h
new file mode 100644
index 0000000..8ef774e
--- /dev/null
+++ b/ComLightLib/server/freeThreadedMarshaller.h
@@ -0,0 +1,29 @@
+#pragma once
+#ifdef _MSC_VER
+#include "../comLightCommon.h"
+
+namespace ComLight
+{
+ namespace details
+ {
+ HRESULT createFreeThreadedMarshaller( IUnknown* pUnkOuter, IUnknown** ppUnkMarshal );
+ bool queryMarshallerInterface( REFIID riid, void **ppvObject, IUnknown* marshaller );
+ }
+}
+
+#define DECLARE_FREE_THREADED_MARSHALLER() \
+private: \
+ComLight::CComPtr<ComLight::IUnknown> m_freeThreadedMarshaller; \
+protected: \
+HRESULT internalFinalConstruct() \
+{ \
+ return ComLight::details::createFreeThreadedMarshaller( getUnknown(), &m_freeThreadedMarshaller ); \
+} \
+bool queryExtraInterfaces( REFIID riid, void **ppvObject ) const \
+{ \
+ return ComLight::details::queryMarshallerInterface( riid, ppvObject, m_freeThreadedMarshaller ); \
+}
+
+#else
+#define DECLARE_FREE_THREADED_MARSHALLER()
+#endif \ No newline at end of file
diff --git a/ComLightLib/server/interfaceMap.h b/ComLightLib/server/interfaceMap.h
new file mode 100644
index 0000000..605ed33
--- /dev/null
+++ b/ComLightLib/server/interfaceMap.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "../utils/typeTraits.hpp"
+
+// Unlike ATL, the interface map is optional for ComLight.
+// If you won't declare a map, the object will support 2 interfaces: IUnknown, and whatever template argument was passed to ObjectRoot class.
+#define BEGIN_COM_MAP() \
+protected: \
+bool implQueryInterface( REFIID iid, void** ppvObject ) {
+
+#define END_COM_MAP() return false; }
+
+namespace ComLight
+{
+ namespace details
+ {
+ template<typename I, typename C>
+ inline bool tryReturnInterface( REFIID iid, C* pThis, void** ppvResult )
+ {
+ static_assert( pointersAssignable<IUnknown, I>(), "Trying to implement an interface that doesn't derive from IUnknown" );
+ static_assert( pointersAssignable<I, C>(), "Declared support for an interface, but the class doesn't implement it" );
+ if( I::iid() != iid )
+ return false;
+ I* const result = pThis;
+ result->AddRef();
+ *ppvResult = result;
+ return true;
+ }
+ }
+}
+
+#define COM_INTERFACE_ENTRY( I ) if( ComLight::details::tryReturnInterface<I>( iid, this, ppvObject ) ) return true; \ No newline at end of file