diff --git a/modules/juce_audio_devices/native/juce_WASAPI_windows.cpp b/modules/juce_audio_devices/native/juce_WASAPI_windows.cpp index c4dd5b8dca..ddb04ae189 100644 --- a/modules/juce_audio_devices/native/juce_WASAPI_windows.cpp +++ b/modules/juce_audio_devices/native/juce_WASAPI_windows.cpp @@ -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 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); } diff --git a/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp b/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp index d0c8c6c63e..301ce06c3b 100644 --- a/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp +++ b/modules/juce_audio_formats/codecs/juce_WindowsMediaAudioFormat.cpp @@ -42,7 +42,7 @@ class JuceIStream final : public ComBaseClassHelper { 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)) { diff --git a/modules/juce_core/native/juce_ComSmartPtr_windows.h b/modules/juce_core/native/juce_ComSmartPtr_windows.h index f20e816edf..e1fe55726c 100644 --- a/modules/juce_core/native/juce_ComSmartPtr_windows.h +++ b/modules/juce_core/native/juce_ComSmartPtr_windows.h @@ -103,30 +103,27 @@ template 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 + ComSmartPtr (const ComSmartPtr& other) : ComSmartPtr (other, true) {} + ComSmartPtr (const ComSmartPtr& other) : ComSmartPtr (other, true) {} + + ~ComSmartPtr() noexcept { release(); } + + template + ComSmartPtr& operator= (const ComSmartPtr& 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 + 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 +auto addComSmartPtrOwner (ObjectType* t) +{ + return ComSmartPtr::addOwner (t); +} + +/** Does not initially increment refcount; assumes t has a positive refcount. */ +template +auto becomeComSmartPtrOwner (ObjectType* t) +{ + return ComSmartPtr::becomeOwner (t); +} + //============================================================================== template 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 ComBaseClassHelper : public ComBaseClassHelperBase { public: - explicit ComBaseClassHelper (unsigned int initialRefCount = 1) - : ComBaseClassHelperBase (initialRefCount) {} + ComBaseClassHelper() = default; JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override { diff --git a/modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp b/modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp index 1a8df792dc..4451743bee 100644 --- a/modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp +++ b/modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp @@ -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 textRenderer (new CustomDirectWriteTextRenderer (fontCollection, text)); + auto textRenderer = becomeComSmartPtrOwner (new CustomDirectWriteTextRenderer (fontCollection, text)); hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0); } diff --git a/modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp b/modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp index 2d2f98a9de..8b23ecd1e4 100644 --- a/modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp +++ b/modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp @@ -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 (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 { - PathGeometrySink() : ComBaseClassHelper (0) {} + PathGeometrySink() = default; void STDMETHODCALLTYPE AddBeziers (const D2D1_BEZIER_SEGMENT* beziers, UINT beziersCount) noexcept override { diff --git a/modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp b/modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp index 3cf18e808c..02d7d5ff9b 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp +++ b/modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp @@ -151,8 +151,7 @@ static auto roleToControlTypeId (AccessibilityRole roleType) //============================================================================== AccessibilityNativeHandle::AccessibilityNativeHandle (AccessibilityHandler& handler) - : ComBaseClassHelper (0), - accessibilityHandler (handler) + : accessibilityHandler (handler) { } diff --git a/modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp b/modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp index be4ef4c1e2..c1c1341bcd 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp +++ b/modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp @@ -65,7 +65,7 @@ class AccessibilityHandler::AccessibilityNativeImpl { public: explicit AccessibilityNativeImpl (AccessibilityHandler& owner) - : accessibilityElement (new AccessibilityNativeHandle (owner)) + : accessibilityElement (becomeComSmartPtrOwner (new AccessibilityNativeHandle (owner))) { ++providerCount; } diff --git a/modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h b/modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h index 694a2069dc..91fd086b00 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h +++ b/modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h @@ -40,7 +40,7 @@ class UIAProviderBase { public: explicit UIAProviderBase (AccessibilityNativeHandle* nativeHandleIn) - : nativeHandle (nativeHandleIn) + : nativeHandle (addComSmartPtrOwner (nativeHandleIn)) { } diff --git a/modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h b/modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h index f1abb75b8f..2fabdd6b44 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h +++ b/modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h @@ -194,7 +194,7 @@ private: public: UIATextRangeProvider (UIATextProvider& textProvider, Range range) : UIAProviderBase (textProvider.getHandler().getNativeImplementation()), - owner (&textProvider), + owner (addComSmartPtrOwner (&textProvider)), selectionRange (range) { } diff --git a/modules/juce_gui_basics/native/juce_FileChooser_windows.cpp b/modules/juce_gui_basics/native/juce_FileChooser_windows.cpp index 7cc95625c0..8433042439 100644 --- a/modules/juce_gui_basics/native/juce_FileChooser_windows.cpp +++ b/modules/juce_gui_basics/native/juce_FileChooser_windows.cpp @@ -296,7 +296,7 @@ private: { HWND hwnd = nullptr; - if (auto window = ComSmartPtr { d }.getInterface()) + if (auto window = addComSmartPtrOwner (d).getInterface()) window->GetWindow (&hwnd); ScopedLock lock (owner.deletingDialog); diff --git a/modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp b/modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp index e708a90262..71b917fd8a 100644 --- a/modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp +++ b/modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp @@ -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; } diff --git a/modules/juce_video/native/juce_CameraDevice_windows.h b/modules/juce_video/native/juce_CameraDevice_windows.h index a34a0430f0..568802fbb5 100644 --- a/modules/juce_video/native/juce_CameraDevice_windows.h +++ b/modules/juce_video/native/juce_CameraDevice_windows.h @@ -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 { - GrabberCallback (Pimpl& p) - : ComBaseClassHelperBase (0), owner (p) {} + explicit GrabberCallback (Pimpl& p) + : owner (p) {} JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override {