2025-11-28 00:35:46 +09:00

240 lines
5.7 KiB
C++

#pragma once
// Class Factory implementation
/*
// Example of usage:
// g_ClassFactories: Array of class factory data.
// Defines a look-up table of CLSIDs and corresponding creation functions.
ClassFactoryData g_ClassFactories[] =
{
{ &CLSID_MyObject, MyObject::CreateInstance }
};
DWORD g_numClassFactories = ARRAY_SIZE(g_ClassFactories);
// Defines the static ClassFactory::m_serverLocks member.
DEFINE_CLASSFACTORY_SERVER_LOCK;
STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void** ppv)
{
ClassFactory *pFactory = NULL;
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; // Default to failure
// Find an entry in our look-up table for the specified CLSID.
for (DWORD index = 0; index < g_numClassFactories; index++)
{
if (*g_ClassFactories[index].pclsid == clsid)
{
// Found an entry. Create a new class factory object.
pFactory = new ClassFactory(g_ClassFactories[index].pfnCreate);
if (pFactory)
{
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
break;
}
}
if (SUCCEEDED(hr))
{
hr = pFactory->QueryInterface(riid, ppv);
}
SAFE_RELEASE(pFactory);
return hr;
}
STDAPI DllCanUnloadNow()
{
if (!ClassFactory::IsLocked())
{
return S_OK;
}
else
{
return S_FALSE;
}
}
*/
namespace MediaFoundationSamples
{
// Function pointer for creating COM objects. (Used by the class factory.)
typedef HRESULT (*CreateInstanceFn)(IUnknown *pUnkOuter, REFIID iid, void **ppv);
// Structure to associate CLSID with object creation function.
struct ClassFactoryData
{
const GUID *pclsid;
CreateInstanceFn pfnCreate;
};
// ClassFactory:
// Implements a class factory for COM objects.
class ClassFactory : public IClassFactory
{
private:
volatile long m_refCount; // Reference count.
static volatile long m_serverLocks; // Number of server locks
CreateInstanceFn m_pfnCreation; // Function to create an instance of the object.
public:
ClassFactory(CreateInstanceFn pfnCreation) : m_pfnCreation(pfnCreation), m_refCount(1)
{
}
static bool IsLocked()
{
return (m_serverLocks != 0);
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_refCount);
}
STDMETHODIMP_(ULONG) Release()
{
assert(m_refCount >= 0);
ULONG uCount = InterlockedDecrement(&m_refCount);
if (uCount == 0)
{
delete this;
}
// Return the temporary variable, not the member
// variable, for thread safety.
return uCount;
}
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
if (NULL == ppv)
{
return E_POINTER;
}
else if (riid == __uuidof(IUnknown))
{
*ppv = static_cast<IUnknown*>(this);
}
else if (riid == __uuidof(IClassFactory))
{
*ppv = static_cast<IClassFactory*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
{
// If the caller is aggregating the object, the caller may only request
// IUknown. (See MSDN documenation for IClassFactory::CreateInstance.)
if (pUnkOuter != NULL)
{
if (riid != __uuidof(IUnknown))
{
return E_NOINTERFACE;
}
}
return m_pfnCreation(pUnkOuter, riid, ppv);
}
STDMETHODIMP LockServer(BOOL lock)
{
if (lock)
{
LockServer();
}
else
{
UnlockServer();
}
return S_OK;
}
// Static methods to lock and unlock the the server.
static void LockServer()
{
InterlockedIncrement(&m_serverLocks);
}
static void UnlockServer()
{
InterlockedDecrement(&m_serverLocks);
}
};
// BaseObjects
// All COM objects that are implemented in the server (DLL) must derive from BaseObject
// so that the server is not unlocked while objects are still active.
class BaseObject
{
public:
BaseObject()
{
ClassFactory::LockServer();
}
virtual ~BaseObject()
{
ClassFactory::UnlockServer();
}
};
// RefCountedObject
// You can use this when implementing IUnknown or any object that uses reference counting.
class RefCountedObject
{
protected:
volatile long m_refCount;
public:
RefCountedObject() : m_refCount(1) {}
virtual ~RefCountedObject()
{
assert(m_refCount == 0);
}
ULONG AddRef()
{
return InterlockedIncrement(&m_refCount);
}
ULONG Release()
{
assert(m_refCount > 0);
ULONG uCount = InterlockedDecrement(&m_refCount);
if (uCount == 0)
{
delete this;
}
return uCount;
}
};
#define DEFINE_CLASSFACTORY_SERVER_LOCK volatile long ClassFactory::m_serverLocks = 0;
}; // namespace MediaFoundationSamples