Fix drag-out losing audio and FX-container drops losing the capture; re-home ingest under shell/actions
This commit is contained in:
@@ -62,6 +62,29 @@ HGLOBAL buildHDrop(const std::vector<std::string>& paths) {
|
||||
return h;
|
||||
}
|
||||
|
||||
// COM reference counts MUST be interlocked. A CF_HDROP target is free to marshal the data
|
||||
// object into another apartment and finish the copy on a background thread AFTER DoDragDrop
|
||||
// has returned (Explorer's async file copy does exactly this). A plain ++/-- there races the
|
||||
// source thread's post-DoDragDrop Release: one lost increment destroys the object — and with
|
||||
// it the source HGLOBAL — before the target reads it, and the drop lands with no file. That
|
||||
// race is intermittent and a retry usually wins it; do not "simplify" these back.
|
||||
inline ULONG comAddRef(volatile LONG& refs) {
|
||||
return static_cast<ULONG>(InterlockedIncrement(&refs));
|
||||
}
|
||||
|
||||
// DoDragDrop requires the calling thread to be OLE-initialized — CoInitialize alone is not
|
||||
// enough, and an uninitialized thread fails the call outright, so the drag never starts.
|
||||
// Relying on REAPER having done it is a first-use hazard: whether it has depends on what else
|
||||
// ran first in the session. OleInitialize is per-thread refcounted, so this is additive to
|
||||
// whatever the host did; we deliberately never OleUninitialize — the extension lives for the
|
||||
// process, and unbalancing a REAPER-owned apartment is the hazard worth avoiding, not this.
|
||||
// RPC_E_CHANGED_MODE means the thread joined an MTA, where OLE drag-drop is unavailable.
|
||||
bool ensureOleForThisThread() {
|
||||
static thread_local int state = 0; // 0 untried, 1 ready, -1 unavailable
|
||||
if (state == 0) state = SUCCEEDED(OleInitialize(nullptr)) ? 1 : -1;
|
||||
return state > 0;
|
||||
}
|
||||
|
||||
// Minimal IDropSource: continue until the (left) button releases or Escape cancels; always
|
||||
// request the copy cursor. This is the standard textbook drop source — no custom feedback.
|
||||
class DropSource final : public IDropSource {
|
||||
@@ -76,11 +99,11 @@ public:
|
||||
*ppv = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return ++refs_; }
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return comAddRef(refs_); }
|
||||
ULONG STDMETHODCALLTYPE Release() override {
|
||||
const ULONG r = --refs_;
|
||||
const LONG r = InterlockedDecrement(&refs_);
|
||||
if (r == 0) delete this;
|
||||
return r;
|
||||
return static_cast<ULONG>(r);
|
||||
}
|
||||
// IDropSource
|
||||
HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL escapePressed, DWORD keyState) override {
|
||||
@@ -92,7 +115,7 @@ public:
|
||||
return DRAGDROP_S_USEDEFAULTCURSORS; // let OLE draw the standard copy cursor
|
||||
}
|
||||
private:
|
||||
ULONG refs_ = 1;
|
||||
volatile LONG refs_ = 1;
|
||||
};
|
||||
|
||||
// Minimal IDataObject exposing exactly one format (CF_HDROP / TYMED_HGLOBAL). The HDROP is
|
||||
@@ -112,11 +135,11 @@ public:
|
||||
*ppv = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return ++refs_; }
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return comAddRef(refs_); }
|
||||
ULONG STDMETHODCALLTYPE Release() override {
|
||||
const ULONG r = --refs_;
|
||||
const LONG r = InterlockedDecrement(&refs_);
|
||||
if (r == 0) delete this;
|
||||
return r;
|
||||
return static_cast<ULONG>(r);
|
||||
}
|
||||
|
||||
// IDataObject — the two that matter for a drag source.
|
||||
@@ -184,7 +207,7 @@ private:
|
||||
(fe.tymed & TYMED_HGLOBAL) &&
|
||||
fe.dwAspect == DVASPECT_CONTENT;
|
||||
}
|
||||
ULONG refs_ = 1;
|
||||
volatile LONG refs_ = 1;
|
||||
HGLOBAL hdrop_ = nullptr;
|
||||
};
|
||||
|
||||
@@ -192,10 +215,8 @@ private:
|
||||
|
||||
bool initiateDragOut(HWND__* /*panelHwnd*/, const std::vector<std::string>& absolutePaths) {
|
||||
if (absolutePaths.empty()) return false;
|
||||
if (!ensureOleForThisThread()) return false;
|
||||
|
||||
// REAPER's main thread is already OLE-initialized (it hosts OLE drag targets); we
|
||||
// deliberately do NOT call OleInitialize — pairing OleUninitialize across a
|
||||
// REAPER-owned apartment is the kind of thing that bites.
|
||||
HGLOBAL hdrop = buildHDrop(absolutePaths);
|
||||
if (!hdrop) return false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user