1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

ComSmartPtr: Make ownership more explicit

COM objects now always start with a refcount of 1, as is convention.
This commit is contained in:
reuk 2024-03-21 19:27:48 +00:00
parent fe9fc0c0e6
commit 1f9ba0682c
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
12 changed files with 78 additions and 47 deletions

View file

@ -623,9 +623,8 @@ private:
if (audioSessionControl != nullptr)
{
sessionEventCallback = new SessionEventCallback (*this);
sessionEventCallback = becomeComSmartPtrOwner (new SessionEventCallback (*this));
audioSessionControl->RegisterAudioSessionNotification (sessionEventCallback);
sessionEventCallback->Release(); // (required because ComBaseClassHelper objects are constructed with a ref count of 1)
}
}
@ -1831,7 +1830,7 @@ private:
{
public:
explicit ChangeNotificationClient (WASAPIAudioIODeviceType* d)
: ComBaseClassHelper (0), device (d) {}
: device (d) {}
JUCE_COMRESULT OnDeviceAdded (LPCWSTR) override { return notify(); }
JUCE_COMRESULT OnDeviceRemoved (LPCWSTR) override { return notify(); }
@ -1859,10 +1858,10 @@ private:
static String getDefaultEndpoint (IMMDeviceEnumerator* enumerator, bool forCapture)
{
String s;
IMMDevice* dev = nullptr;
ComSmartPtr<IMMDevice> dev;
if (check (enumerator->GetDefaultAudioEndpoint (forCapture ? eCapture : eRender,
eMultimedia, &dev)))
eMultimedia, dev.resetAndGetPointerAddress())))
{
WCHAR* deviceId = nullptr;
@ -1871,8 +1870,6 @@ private:
s = deviceId;
CoTaskMemFree (deviceId);
}
dev->Release();
}
return s;
@ -1886,7 +1883,7 @@ private:
if (! check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator))))
return {};
notifyClient = new ChangeNotificationClient (this);
notifyClient = becomeComSmartPtrOwner (new ChangeNotificationClient (this));
enumerator->RegisterEndpointNotificationCallback (notifyClient);
}

View file

@ -42,7 +42,7 @@ class JuceIStream final : public ComBaseClassHelper<IStream>
{
public:
JuceIStream (InputStream& in) noexcept
: ComBaseClassHelper (0), source (in)
: source (in)
{
}
@ -153,7 +153,7 @@ public:
HRESULT hr = wmCreateSyncReader (nullptr, WMT_RIGHT_PLAYBACK, wmSyncReader.resetAndGetPointerAddress());
if (SUCCEEDED (hr))
hr = wmSyncReader->OpenStream (new JuceIStream (*input));
hr = wmSyncReader->OpenStream (becomeComSmartPtrOwner (new JuceIStream (*input)));
if (SUCCEEDED (hr))
{

View file

@ -103,30 +103,27 @@ template <class ComClass>
class ComSmartPtr
{
public:
ComSmartPtr() noexcept {}
ComSmartPtr (ComClass* obj) : p (obj) { if (p) p->AddRef(); }
ComSmartPtr (const ComSmartPtr& other) : p (other.p) { if (p) p->AddRef(); }
~ComSmartPtr() { release(); }
ComSmartPtr() noexcept = default;
ComSmartPtr (std::nullptr_t) noexcept {}
template <typename U>
ComSmartPtr (const ComSmartPtr<U>& other) : ComSmartPtr (other, true) {}
ComSmartPtr (const ComSmartPtr& other) : ComSmartPtr (other, true) {}
~ComSmartPtr() noexcept { release(); }
template <typename U>
ComSmartPtr& operator= (const ComSmartPtr<U>& newP) { ComSmartPtr copy { newP }; std::swap (copy.p, p); return *this; }
ComSmartPtr& operator= (const ComSmartPtr& newP) { ComSmartPtr copy { newP }; std::swap (copy.p, p); return *this; }
operator ComClass*() const noexcept { return p; }
ComClass& operator*() const noexcept { return *p; }
ComClass* operator->() const noexcept { return p; }
ComSmartPtr& operator= (ComClass* const newP)
{
if (newP != nullptr) newP->AddRef();
release();
p = newP;
return *this;
}
ComSmartPtr& operator= (const ComSmartPtr& newP) { return operator= (newP.p); }
// Releases and nullifies this pointer and returns its address
ComClass** resetAndGetPointerAddress()
{
release();
p = nullptr;
return &p;
}
@ -160,30 +157,70 @@ public:
if (QueryInterface (destObject) == S_OK)
return destObject;
return nullptr;
return {};
}
/** Increments refcount. */
static auto addOwner (ComClass* t)
{
return ComSmartPtr (t, true);
}
/** Does not initially increment refcount; assumes t has a positive refcount. */
static auto becomeOwner (ComClass* t)
{
return ComSmartPtr (t, false);
}
private:
ComClass* p = nullptr;
template <typename U>
friend class ComSmartPtr;
void release() { if (p != nullptr) p->Release(); }
ComSmartPtr (ComClass* object, bool autoAddRef) noexcept
: p (object)
{
if (p != nullptr && autoAddRef)
p->AddRef();
}
void release()
{
if (auto* q = std::exchange (p, nullptr))
q->Release();
}
ComClass** operator&() noexcept; // private to avoid it being used accidentally
ComClass* p = nullptr;
};
/** Increments refcount. */
template <class ObjectType>
auto addComSmartPtrOwner (ObjectType* t)
{
return ComSmartPtr<ObjectType>::addOwner (t);
}
/** Does not initially increment refcount; assumes t has a positive refcount. */
template <class ObjectType>
auto becomeComSmartPtrOwner (ObjectType* t)
{
return ComSmartPtr<ObjectType>::becomeOwner (t);
}
//==============================================================================
template <class First, class... ComClasses>
class ComBaseClassHelperBase : public First, public ComClasses...
{
public:
ComBaseClassHelperBase (unsigned int initialRefCount) : refCount (initialRefCount) {}
ComBaseClassHelperBase() = default;
virtual ~ComBaseClassHelperBase() = default;
ULONG STDMETHODCALLTYPE AddRef() override { return ++refCount; }
ULONG STDMETHODCALLTYPE Release() override { auto r = --refCount; if (r == 0) delete this; return r; }
protected:
ULONG refCount;
ULONG refCount = 1;
JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override
{
@ -212,8 +249,7 @@ template <class... ComClasses>
class ComBaseClassHelper : public ComBaseClassHelperBase<ComClasses...>
{
public:
explicit ComBaseClassHelper (unsigned int initialRefCount = 1)
: ComBaseClassHelperBase<ComClasses...> (initialRefCount) {}
ComBaseClassHelper() = default;
JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override
{

View file

@ -42,8 +42,7 @@ namespace DirectWriteTypeLayout
{
public:
CustomDirectWriteTextRenderer (IDWriteFontCollection& fonts, const AttributedString& as)
: ComBaseClassHelper (0),
attributedString (as),
: attributedString (as),
fontCollection (fonts)
{
}
@ -432,7 +431,7 @@ namespace DirectWriteTypeLayout
layout.ensureStorageAllocated ((int) actualLineCount);
{
ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection, text));
auto textRenderer = becomeComSmartPtrOwner (new CustomDirectWriteTextRenderer (fontCollection, text));
hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0);
}

View file

@ -270,7 +270,7 @@ public:
{
jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty
auto glyphIndex = (UINT16) glyphNumber;
ComSmartPtr<PathGeometrySink> pathGeometrySink (new PathGeometrySink());
auto pathGeometrySink = becomeComSmartPtrOwner (new PathGeometrySink());
dwFontFace->GetGlyphRunOutline (1024.0f, &glyphIndex, nullptr, nullptr,
1, false, false, pathGeometrySink);
@ -296,7 +296,7 @@ private:
struct PathGeometrySink final : public ComBaseClassHelper<IDWriteGeometrySink>
{
PathGeometrySink() : ComBaseClassHelper (0) {}
PathGeometrySink() = default;
void STDMETHODCALLTYPE AddBeziers (const D2D1_BEZIER_SEGMENT* beziers, UINT beziersCount) noexcept override
{

View file

@ -151,8 +151,7 @@ static auto roleToControlTypeId (AccessibilityRole roleType)
//==============================================================================
AccessibilityNativeHandle::AccessibilityNativeHandle (AccessibilityHandler& handler)
: ComBaseClassHelper (0),
accessibilityHandler (handler)
: accessibilityHandler (handler)
{
}

View file

@ -65,7 +65,7 @@ class AccessibilityHandler::AccessibilityNativeImpl
{
public:
explicit AccessibilityNativeImpl (AccessibilityHandler& owner)
: accessibilityElement (new AccessibilityNativeHandle (owner))
: accessibilityElement (becomeComSmartPtrOwner (new AccessibilityNativeHandle (owner)))
{
++providerCount;
}

View file

@ -40,7 +40,7 @@ class UIAProviderBase
{
public:
explicit UIAProviderBase (AccessibilityNativeHandle* nativeHandleIn)
: nativeHandle (nativeHandleIn)
: nativeHandle (addComSmartPtrOwner (nativeHandleIn))
{
}

View file

@ -194,7 +194,7 @@ private:
public:
UIATextRangeProvider (UIATextProvider& textProvider, Range<int> range)
: UIAProviderBase (textProvider.getHandler().getNativeImplementation()),
owner (&textProvider),
owner (addComSmartPtrOwner (&textProvider)),
selectionRange (range)
{
}

View file

@ -296,7 +296,7 @@ private:
{
HWND hwnd = nullptr;
if (auto window = ComSmartPtr<IFileDialog> { d }.getInterface<IOleWindow>())
if (auto window = addComSmartPtrOwner (d).getInterface<IOleWindow>())
window->GetWindow (&hwnd);
ScopedLock lock (owner.deletingDialog);

View file

@ -75,7 +75,7 @@ namespace ActiveXHelpers
JUCE_COMRESULT GetBorder (LPRECT) override { return E_NOTIMPL; }
JUCE_COMRESULT RequestBorderSpace (LPCBORDERWIDTHS) override { return E_NOTIMPL; }
JUCE_COMRESULT SetBorderSpace (LPCBORDERWIDTHS) override { return E_NOTIMPL; }
JUCE_COMRESULT SetActiveObject (IOleInPlaceActiveObject* a, LPCOLESTR) override { activeObject = a; return S_OK; }
JUCE_COMRESULT SetActiveObject (IOleInPlaceActiveObject* a, LPCOLESTR) override { activeObject = addComSmartPtrOwner (a); return S_OK; }
JUCE_COMRESULT InsertMenus (HMENU, LPOLEMENUGROUPWIDTHS) override { return E_NOTIMPL; }
JUCE_COMRESULT SetMenu (HMENU, HOLEMENU, HWND) override { return S_OK; }
JUCE_COMRESULT RemoveMenus (HMENU) override { return E_NOTIMPL; }

View file

@ -111,7 +111,7 @@ struct CameraDevice::Pimpl : public ChangeBroadcaster
sampleGrabber->SetMediaType (&mt);
}
callback = new GrabberCallback (*this);
callback = becomeComSmartPtrOwner (new GrabberCallback (*this));
hr = sampleGrabber->SetCallback (callback, 1);
hr = graphBuilder->AddFilter (sampleGrabberBase, _T ("Sample Grabber"));
@ -536,8 +536,8 @@ struct CameraDevice::Pimpl : public ChangeBroadcaster
struct GrabberCallback : public ComBaseClassHelperBase<ComTypes::ISampleGrabberCB>
{
GrabberCallback (Pimpl& p)
: ComBaseClassHelperBase (0), owner (p) {}
explicit GrabberCallback (Pimpl& p)
: owner (p) {}
JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override
{