Repository: microsoft/terminal (language: cpp)

Issue:
can't copy and paste anything
### Windows Terminal version

1.19.10821.0

### Windows build number

22631.3296

### Other Software

_No response_

### Steps to reproduce

Use the right mouse button or CTRL+c or CTRL+v to copy and paste.

It will expire at random intervals.
During this period the copy and paste functionality of other software works fine.
The copy and paste function returns to normal after about ten minutes of inactivity.

Frequency of occurrence: Every few hours.

### Expected Behavior

copy paste behavior

### Actual Behavior

No response


Discussion / hints:
Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

### Open similar issues:

- [Rewrite the copy-to-clipboard functionality to use the Win32 functions (#16715)](https://github.com/microsoft/terminal/issues/16715),  similarity score: 0.77

### Closed similar issues:
- [Text copying does not work (#16576)](https://github.com/microsoft/terminal/issues/16576),  similarity score: 0.78
- [Can not copy in WSL (#12215)](https://github.com/microsoft/terminal/issues/12215),  similarity score: 0.78
- [Copy paste is not working  (#2340)](https://github.com/microsoft/terminal/issues/2340),  similarity score: 0.77
- [Copying text from terminal doesn't seem to work on Windows 11 (#11475)](https://github.com/microsoft/terminal/issues/11475),  similarity score: 0.77

> Note: You can give me feedback by thumbs upping or thumbs downing this comment.
I got the same issue. It happens sporadically. It's annoying.

In my case, paste is working to terminal if copying text from other application. But copy text does not work in terminal.
Ditto. Incredibly annoying. Paste works. Copy does not (either through Ctrl+Ins or with auto-copy selection).
I got the same issue on my side even i remove all the key bindings just remain ctrl + c/v for copy paste it still not working..
My current Windows Terminal Version: 1.19.10573.0
I'm facing the same issue as well with version 1.19.10573.0
I have exactly the same issue as described in the original post. It severely affects my productivity. 

Windows Terminal version
1.19.10573.0

Windows build number
22631.3296
Wait, just to clarify - when y'all are pasting, are you seeing the same, seemingly random text from VsCode? Or is that just a red herring?

We did some work recently around here - in preview 1.19 it looks like we started merging stuff:
* #15360 - this should have only affected pasting into the terminal, not copying out of it
* #16457 (for 1.20, which was backported to 1.19 stable in #16618) - this should have only changed copy/paste for _conhost_, not the Terminal

For additional info: What are you running in the Terminal? CMD / PowerShell / WSL? Vim? 
@zadjii-msft My bad, just to clarify I see the same behavior as OP (quoted below). The VSCode part is not true in my case.

> Use the right mouse button or CTRL+c or CTRL+v to copy and paste.
> 
> It will expire at random intervals.
> During this period the copy and paste functionality of other software works fine.
> The copy and paste function returns to normal after about ten minutes of inactivity.
> 
> Frequency of occurrence: Every few hours.

I am sure that both copy and paste are affected. When I select the text in terminal and try to copy, the selection gets reset when I press CTRL + C but I do not see the text I've copied in Windows Clipboard history. This happens to me in both PowerShell and WSL from what I've observed. (PowerShell 7.4.1 and WSL 2 with Ubuntu)

I have had this issue for over a week now.

Fix patch:
diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
index 591fc6906a0..002ec3d7f24 100644
--- a/src/cascadia/TerminalApp/TerminalPage.cpp
+++ b/src/cascadia/TerminalApp/TerminalPage.cpp
@@ -1640,10 +1640,6 @@ namespace winrt::TerminalApp::implementation
     {
         term.RaiseNotice({ this, &TerminalPage::_ControlNoticeRaisedHandler });
 
-        // Add an event handler when the terminal's selection wants to be copied.
-        // When the text buffer data is retrieved, we'll copy the data into the Clipboard
-        term.CopyToClipboard({ this, &TerminalPage::_CopyToClipboardHandler });
-
         // Add an event handler when the terminal wants to paste data from the Clipboard.
         term.PasteFromClipboard({ this, &TerminalPage::_PasteFromClipboardHandler });
 
@@ -2545,54 +2541,6 @@ namespace winrt::TerminalApp::implementation
         return dimension;
     }
 
-    // Method Description:
-    // - Place `copiedData` into the clipboard as text. Triggered when a
-    //   terminal control raises its CopyToClipboard event.
-    // Arguments:
-    // - copiedData: the new string content to place on the clipboard.
-    winrt::fire_and_forget TerminalPage::_CopyToClipboardHandler(const IInspectable /*sender*/,
-                                                                 const CopyToClipboardEventArgs copiedData)
-    {
-        co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::High);
-
-        auto dataPack = DataPackage();
-        dataPack.RequestedOperation(DataPackageOperation::Copy);
-
-        const auto copyFormats = copiedData.Formats() != nullptr ?
-                                     copiedData.Formats().Value() :
-                                     static_cast<CopyFormat>(0);
-
-        // copy text to dataPack
-        dataPack.SetText(copiedData.Text());
-
-        if (WI_IsFlagSet(copyFormats, CopyFormat::HTML))
-        {
-            // copy html to dataPack
-            const auto htmlData = copiedData.Html();
-            if (!htmlData.empty())
-            {
-                dataPack.SetHtmlFormat(htmlData);
-            }
-        }
-
-        if (WI_IsFlagSet(copyFormats, CopyFormat::RTF))
-        {
-            // copy rtf data to dataPack
-            const auto rtfData = copiedData.Rtf();
-            if (!rtfData.empty())
-            {
-                dataPack.SetRtf(rtfData);
-            }
-        }
-
-        try
-        {
-            Clipboard::SetContent(dataPack);
-            Clipboard::Flush();
-        }
-        CATCH_LOG();
-    }
-
     static wil::unique_close_clipboard_call _openClipboard(HWND hwnd)
     {
         bool success = false;
diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h
index 227f28edbb5..a78da4d6a1d 100644
--- a/src/cascadia/TerminalApp/TerminalPage.h
+++ b/src/cascadia/TerminalApp/TerminalPage.h
@@ -392,7 +392,6 @@ namespace winrt::TerminalApp::implementation
         void _ScrollToBufferEdge(ScrollDirection scrollDirection);
         void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::Control::KeyChord& keyChord);
 
-        winrt::fire_and_forget _CopyToClipboardHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::CopyToClipboardEventArgs copiedData);
         winrt::fire_and_forget _PasteFromClipboardHandler(const IInspectable sender,
                                                           const Microsoft::Terminal::Control::PasteFromClipboardEventArgs eventArgs);
 
diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp
index 4c36320d9b2..02cd7478c72 100644
--- a/src/cascadia/TerminalControl/ControlCore.cpp
+++ b/src/cascadia/TerminalControl/ControlCore.cpp
@@ -1221,11 +1221,87 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         _updateSelectionUI();
     }
 
+    static wil::unique_close_clipboard_call _openClipboard(HWND hwnd)
+    {
+        bool success = false;
+
+        // OpenClipboard may fail to acquire the internal lock --> retry.
+        for (DWORD sleep = 10;; sleep *= 2)
+        {
+            if (OpenClipboard(hwnd))
+            {
+                success = true;
+                break;
+            }
+            // 10 iterations
+            if (sleep > 10000)
+            {
+                break;
+            }
+            Sleep(sleep);
+        }
+
+        return wil::unique_close_clipboard_call{ success };
+    }
+
+    static void _copyToClipboard(const UINT format, const void* src, const size_t bytes)
+    {
+        wil::unique_hglobal handle{ THROW_LAST_ERROR_IF_NULL(GlobalAlloc(GMEM_MOVEABLE, bytes)) };
+
+        const auto locked = GlobalLock(handle.get());
+        memcpy(locked, src, bytes);
+        GlobalUnlock(handle.get());
+
+        THROW_LAST_ERROR_IF_NULL(SetClipboardData(format, handle.get()));
+        handle.release();
+    }
+
+    static void _copyToClipboardRegisteredFormat(const wchar_t* format, const void* src, size_t bytes)
+    {
+        const auto id = RegisterClipboardFormatW(format);
+        if (!id)
+        {
+            LOG_LAST_ERROR();
+            return;
+        }
+        _copyToClipboard(id, src, bytes);
+    }
+
+    static void copyToClipboard(wil::zwstring_view text, std::string_view html, std::string_view rtf)
+    {
+        const auto clipboard = _openClipboard(nullptr);
+        if (!clipboard)
+        {
+            LOG_LAST_ERROR();
+            return;
+        }
+
+        EmptyClipboard();
+
+        if (!text.empty())
+        {
+            // As per: https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats
+            //   CF_UNICODETEXT: [...] A null character signals the end of the data.
+            // --> We add +1 to the length. This works because .c_str() is null-terminated.
+            _copyToClipboard(CF_UNICODETEXT, text.c_str(), (text.size() + 1) * sizeof(wchar_t));
+        }
+
+        if (!html.empty())
+        {
+            _copyToClipboardRegisteredFormat(L"HTML Format", html.data(), html.size());
+        }
+
+        if (!rtf.empty())
+        {
+            _copyToClipboardRegisteredFormat(L"Rich Text Format", rtf.data(), rtf.size());
+        }
+    }
+
     // Called when the Terminal wants to set something to the clipboard, i.e.
     // when an OSC 52 is emitted.
-    void ControlCore::_terminalCopyToClipboard(std::wstring_view wstr)
+    void ControlCore::_terminalCopyToClipboard(wil::zwstring_view wstr)
     {
-        CopyToClipboard.raise(*this, winrt::make<implementation::CopyToClipboardEventArgs>(winrt::hstring{ wstr }));
+        copyToClipboard(wstr, {}, {});
     }
 
     // Method Description:
@@ -1238,31 +1314,29 @@ namespace winrt::Microsoft::Terminal::Control::implementation
     bool ControlCore::CopySelectionToClipboard(bool singleLine,
                                                const Windows::Foundation::IReference<CopyFormat>& formats)
     {
-        const auto lock = _terminal->LockForWriting();
-
-        // no selection --> nothing to copy
-        if (!_terminal->IsSelectionActive())
+        ::Microsoft::Terminal::Core::Terminal::TextCopyData payload;
         {
-            return false;
-        }
+            const auto lock = _terminal->LockForWriting();
 
-        // use action's copyFormatting if it's present, else fallback to globally
-        // set copyFormatting.
-        const auto copyFormats = formats != nullptr ? formats.Value() : _settings->CopyFormatting();
+            // no selection --> nothing to copy
+            if (!_terminal->IsSelectionActive())
+            {
+                return false;
+            }
 
-        const auto copyHtml = WI_IsFlagSet(copyFormats, CopyFormat::HTML);
-        const auto copyRtf = WI_IsFlagSet(copyFormats, CopyFormat::RTF);
+            // use action's copyFormatting if it's present, else fallback to globally
+            // set copyFormatting.
+            const auto copyFormats = formats != nullptr ? formats.Value() : _settings->CopyFormatting();
 
-        // extract text from buffer
-        // RetrieveSelectedTextFromBuffer will lock while it's reading
-        const auto& [textData, htmlData, rtfData] = _terminal->RetrieveSelectedTextFromBuffer(singleLine, copyHtml, copyRtf);
-
-        // send data up for clipboard
-        CopyToClipboard.raise(*this,
-                              winrt::make<CopyToClipboardEventArgs>(winrt::hstring{ textData },
-                                                                    winrt::to_hstring(htmlData),
-                                                                    winrt::to_hstring(rtfData),
-                                                                    copyFormats));
+            const auto copyHtml = WI_IsFlagSet(copyFormats, CopyFormat::HTML);
+            const auto copyRtf = WI_IsFlagSet(copyFormats, CopyFormat::RTF);
+
+            // extract text from buffer
+            // RetrieveSelectedTextFromBuffer will lock while it's reading
+            payload = _terminal->RetrieveSelectedTextFromBuffer(singleLine, copyHtml, copyRtf);
+        }
+
+        copyToClipboard(payload.plainText, payload.html, payload.rtf);
         return true;
     }
 
diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h
index ee0d68f6a8a..a5942372900 100644
--- a/src/cascadia/TerminalControl/ControlCore.h
+++ b/src/cascadia/TerminalControl/ControlCore.h
@@ -266,7 +266,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         // clang-format off
         til::typed_event<IInspectable, Control::FontSizeChangedArgs> FontSizeChanged;
 
-        til::typed_event<IInspectable, Control::CopyToClipboardEventArgs> CopyToClipboard;
         til::typed_event<IInspectable, Control::TitleChangedEventArgs> TitleChanged;
         til::typed_event<> WarningBell;
         til::typed_event<> TabColorChanged;
@@ -371,7 +370,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         void _sendInputToConnection(std::wstring_view wstr);
 
 #pragma region TerminalCoreCallbacks
-        void _terminalCopyToClipboard(std::wstring_view wstr);
+        void _terminalCopyToClipboard(wil::zwstring_view wstr);
         void _terminalWarningBell();
         void _terminalTitleChanged(std::wstring_view wstr);
         void _terminalScrollPositionChanged(const int viewTop,
diff --git a/src/cascadia/TerminalControl/ControlCore.idl b/src/cascadia/TerminalControl/ControlCore.idl
index 01223fb1a14..632d2d73751 100644
--- a/src/cascadia/TerminalControl/ControlCore.idl
+++ b/src/cascadia/TerminalControl/ControlCore.idl
@@ -160,7 +160,6 @@ namespace Microsoft.Terminal.Control
         Boolean ShouldShowSelectOutput();
 
         // These events are called from some background thread
-        event Windows.Foundation.TypedEventHandler<Object, CopyToClipboardEventArgs> CopyToClipboard;
         event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
         event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
         event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
diff --git a/src/cascadia/TerminalControl/EventArgs.cpp b/src/cascadia/TerminalControl/EventArgs.cpp
index 93e147feaa8..730545d42a2 100644
--- a/src/cascadia/TerminalControl/EventArgs.cpp
+++ b/src/cascadia/TerminalControl/EventArgs.cpp
@@ -5,7 +5,6 @@
 #include "EventArgs.h"
 #include "FontSizeChangedArgs.g.cpp"
 #include "TitleChangedEventArgs.g.cpp"
-#include "CopyToClipboardEventArgs.g.cpp"
 #include "ContextMenuRequestedEventArgs.g.cpp"
 #include "PasteFromClipboardEventArgs.g.cpp"
 #include "OpenHyperlinkEventArgs.g.cpp"
diff --git a/src/cascadia/TerminalControl/EventArgs.h b/src/cascadia/TerminalControl/EventArgs.h
index 2ed2c2b828b..33c215cb3bc 100644
--- a/src/cascadia/TerminalControl/EventArgs.h
+++ b/src/cascadia/TerminalControl/EventArgs.h
@@ -5,7 +5,6 @@
 
 #include "FontSizeChangedArgs.g.h"
 #include "TitleChangedEventArgs.g.h"
-#include "CopyToClipboardEventArgs.g.h"
 #include "ContextMenuRequestedEventArgs.g.h"
 #include "PasteFromClipboardEventArgs.g.h"
 #include "OpenHyperlinkEventArgs.g.h"
@@ -47,33 +46,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         WINRT_PROPERTY(hstring, Title);
     };
 
-    struct CopyToClipboardEventArgs : public CopyToClipboardEventArgsT<CopyToClipboardEventArgs>
-    {
-    public:
-        CopyToClipboardEventArgs(hstring text) :
-            _text(text),
-            _html(),
-            _rtf(),
-            _formats(static_cast<CopyFormat>(0)) {}
-
-        CopyToClipboardEventArgs(hstring text, hstring html, hstring rtf, Windows::Foundation::IReference<CopyFormat> formats) :
-            _text(text),
-            _html(html),
-            _rtf(rtf),
-            _formats(formats) {}
-
-        hstring Text() { return _text; };
-        hstring Html() { return _html; };
-        hstring Rtf() { return _rtf; };
-        Windows::Foundation::IReference<CopyFormat> Formats() { return _formats; };
-
-    private:
-        hstring _text;
-        hstring _html;
-        hstring _rtf;
-        Windows::Foundation::IReference<CopyFormat> _formats;
-    };
-
     struct ContextMenuRequestedEventArgs : public ContextMenuRequestedEventArgsT<ContextMenuRequestedEventArgs>
     {
     public:
diff --git a/src/cascadia/TerminalControl/EventArgs.idl b/src/cascadia/TerminalControl/EventArgs.idl
index 92784fc6414..958b3e15a64 100644
--- a/src/cascadia/TerminalControl/EventArgs.idl
+++ b/src/cascadia/TerminalControl/EventArgs.idl
@@ -24,14 +24,6 @@ namespace Microsoft.Terminal.Control
         Int32 Height { get; };
     }
 
-    runtimeclass CopyToClipboardEventArgs
-    {
-        String Text { get; };
-        String Html { get; };
-        String Rtf { get; };
-        Windows.Foundation.IReference<CopyFormat> Formats { get; };
-    }
-
     runtimeclass ContextMenuRequestedEventArgs
     {
         Windows.Foundation.Point Position { get; };
diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp
index ec9807dcd08..de565d033e6 100644
--- a/src/cascadia/TerminalControl/TermControl.cpp
+++ b/src/cascadia/TerminalControl/TermControl.cpp
@@ -93,7 +93,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         _revokers.ContextMenuRequested = _interactivity.ContextMenuRequested(winrt::auto_revoke, { get_weak(), &TermControl::_contextMenuHandler });
 
         // "Bubbled" events - ones we want to handle, by raising our own event.
-        _revokers.CopyToClipboard = _core.CopyToClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleCopyToClipboard });
         _revokers.TitleChanged = _core.TitleChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleTitleChanged });
         _revokers.TabColorChanged = _core.TabColorChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleTabColorChanged });
         _revokers.TaskbarProgressChanged = _core.TaskbarProgressChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleSetTaskbarProgress });
diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h
index a12aa964664..24142dc8a7b 100644
--- a/src/cascadia/TerminalControl/TermControl.h
+++ b/src/cascadia/TerminalControl/TermControl.h
@@ -184,7 +184,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         // UNDER NO CIRCUMSTANCES SHOULD YOU ADD A (PROJECTED_)FORWARDED_TYPED_EVENT HERE
         // Those attach the handler to the core directly, and will explode if
         // the core ever gets detached & reattached to another window.
-        BUBBLED_FORWARDED_TYPED_EVENT(CopyToClipboard,        IInspectable, Control::CopyToClipboardEventArgs);
         BUBBLED_FORWARDED_TYPED_EVENT(TitleChanged,           IInspectable, Control::TitleChangedEventArgs);
         BUBBLED_FORWARDED_TYPED_EVENT(TabColorChanged,        IInspectable, IInspectable);
         BUBBLED_FORWARDED_TYPED_EVENT(SetTaskbarProgress,     IInspectable, IInspectable);
@@ -398,7 +397,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
             Control::ControlCore::FoundMatch_revoker FoundMatch;
             Control::ControlCore::UpdateSelectionMarkers_revoker UpdateSelectionMarkers;
             Control::ControlCore::OpenHyperlink_revoker coreOpenHyperlink;
-            Control::ControlCore::CopyToClipboard_revoker CopyToClipboard;
             Control::ControlCore::TitleChanged_revoker TitleChanged;
             Control::ControlCore::TabColorChanged_revoker TabColorChanged;
             Control::ControlCore::TaskbarProgressChanged_revoker TaskbarProgressChanged;
diff --git a/src/cascadia/TerminalControl/TermControl.idl b/src/cascadia/TerminalControl/TermControl.idl
index 8a91707c3af..d42afeffc28 100644
--- a/src/cascadia/TerminalControl/TermControl.idl
+++ b/src/cascadia/TerminalControl/TermControl.idl
@@ -53,7 +53,6 @@ namespace Microsoft.Terminal.Control
         Microsoft.Terminal.Control.IControlSettings Settings { get; };
 
         event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
-        event Windows.Foundation.TypedEventHandler<Object, CopyToClipboardEventArgs> CopyToClipboard;
         event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
         event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
         event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp
index 4a6c1187da5..331bd64509c 100644
--- a/src/cascadia/TerminalCore/Terminal.cpp
+++ b/src/cascadia/TerminalCore/Terminal.cpp
@@ -1117,7 +1117,7 @@ void Terminal::SetTitleChangedCallback(std::function<void(std::wstring_view)> pf
     _pfnTitleChanged.swap(pfn);
 }
 
-void Terminal::SetCopyToClipboardCallback(std::function<void(std::wstring_view)> pfn) noexcept
+void Terminal::SetCopyToClipboardCallback(std::function<void(wil::zwstring_view)> pfn) noexcept
 {
     _pfnCopyToClipboard.swap(pfn);
 }
diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp
index b10c0d893ac..d90e5842593 100644
--- a/src/cascadia/TerminalCore/Terminal.hpp
+++ b/src/cascadia/TerminalCore/Terminal.hpp
@@ -144,7 +144,7 @@ class Microsoft::Terminal::Core::Terminal final :
     bool ResizeWindow(const til::CoordType width, const til::CoordType height) noexcept override;
     void SetConsoleOutputCP(const unsigned int codepage) noexcept override;
     unsigned int GetConsoleOutputCP() const noexcept override;
-    void CopyToClipboard(std::wstring_view content) override;
+    void CopyToClipboard(wil::zwstring_view content) override;
     void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
     void SetWorkingDirectory(std::wstring_view uri) override;
     void PlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) override;
@@ -231,7 +231,7 @@ class Microsoft::Terminal::Core::Terminal final :
     void SetWriteInputCallback(std::function<void(std::wstring_view)> pfn) noexcept;
     void SetWarningBellCallback(std::function<void()> pfn) noexcept;
     void SetTitleChangedCallback(std::function<void(std::wstring_view)> pfn) noexcept;
-    void SetCopyToClipboardCallback(std::function<void(std::wstring_view)> pfn) noexcept;
+    void SetCopyToClipboardCallback(std::function<void(wil::zwstring_view)> pfn) noexcept;
     void SetScrollPositionChangedCallback(std::function<void(const int, const int, const int)> pfn) noexcept;
     void SetCursorPositionChangedCallback(std::function<void()> pfn) noexcept;
     void TaskbarProgressChangedCallback(std::function<void()> pfn) noexcept;
@@ -330,7 +330,7 @@ class Microsoft::Terminal::Core::Terminal final :
     std::function<void(std::wstring_view)> _pfnWriteInput;
     std::function<void()> _pfnWarningBell;
     std::function<void(std::wstring_view)> _pfnTitleChanged;
-    std::function<void(std::wstring_view)> _pfnCopyToClipboard;
+    std::function<void(wil::zwstring_view)> _pfnCopyToClipboard;
 
     // I've specifically put this instance here as it requires
     //   alignas(std::hardware_destructive_interference_size)
diff --git a/src/cascadia/TerminalCore/TerminalApi.cpp b/src/cascadia/TerminalCore/TerminalApi.cpp
index 9a5ea2221ac..a052bc71a31 100644
--- a/src/cascadia/TerminalCore/TerminalApi.cpp
+++ b/src/cascadia/TerminalCore/TerminalApi.cpp
@@ -113,7 +113,7 @@ unsigned int Terminal::GetConsoleOutputCP() const noexcept
     return CP_UTF8;
 }
 
-void Terminal::CopyToClipboard(std::wstring_view content)
+void Terminal::CopyToClipboard(wil::zwstring_view content)
 {
     _pfnCopyToClipboard(content);
 }
diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp
index 70b270e3cd8..e7128027237 100644
--- a/src/host/outputStream.cpp
+++ b/src/host/outputStream.cpp
@@ -251,7 +251,7 @@ unsigned int ConhostInternalGetSet::GetConsoleOutputCP() const
 // - content - the text to be copied.
 // Return Value:
 // - <none>
-void ConhostInternalGetSet::CopyToClipboard(const std::wstring_view /*content*/)
+void ConhostInternalGetSet::CopyToClipboard(const wil::zwstring_view /*content*/)
 {
     // TODO
 }
diff --git a/src/host/outputStream.hpp b/src/host/outputStream.hpp
index 45ea6052e21..dafd8511107 100644
--- a/src/host/outputStream.hpp
+++ b/src/host/outputStream.hpp
@@ -58,7 +58,7 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal::
     void SetConsoleOutputCP(const unsigned int codepage) override;
     unsigned int GetConsoleOutputCP() const override;
 
-    void CopyToClipboard(const std::wstring_view content) override;
+    void CopyToClipboard(const wil::zwstring_view content) override;
     void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
     void SetWorkingDirectory(const std::wstring_view uri) override;
     void PlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) override;
diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp
index d0c96b6949e..eed892f5a94 100644
--- a/src/terminal/adapter/ITermDispatch.hpp
+++ b/src/terminal/adapter/ITermDispatch.hpp
@@ -123,7 +123,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch
     virtual bool SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) = 0; // DECSCUSR
     virtual bool SetCursorColor(const COLORREF color) = 0; // OSCSetCursorColor, OSCResetCursorColor
 
-    virtual bool SetClipboard(std::wstring_view content) = 0; // OSCSetClipboard
+    virtual bool SetClipboard(wil::zwstring_view content) = 0; // OSCSetClipboard
 
     // DTTERM_WindowManipulation
     virtual bool WindowManipulation(const DispatchTypes::WindowManipulationType function,
diff --git a/src/terminal/adapter/ITerminalApi.hpp b/src/terminal/adapter/ITerminalApi.hpp
index 3375a968b04..3cc94921629 100644
--- a/src/terminal/adapter/ITerminalApi.hpp
+++ b/src/terminal/adapter/ITerminalApi.hpp
@@ -70,7 +70,7 @@ namespace Microsoft::Console::VirtualTerminal
         virtual void SetConsoleOutputCP(const unsigned int codepage) = 0;
         virtual unsigned int GetConsoleOutputCP() const = 0;
 
-        virtual void CopyToClipboard(const std::wstring_view content) = 0;
+        virtual void CopyToClipboard(const wil::zwstring_view content) = 0;
         virtual void SetTaskbarProgress(const DispatchTypes::TaskbarState state, const size_t progress) = 0;
         virtual void SetWorkingDirectory(const std::wstring_view uri) = 0;
         virtual void PlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) = 0;
diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp
index dfe540936d0..a35d994dc07 100644
--- a/src/terminal/adapter/adaptDispatch.cpp
+++ b/src/terminal/adapter/adaptDispatch.cpp
@@ -3394,7 +3394,7 @@ bool AdaptDispatch::SetCursorColor(const COLORREF cursorColor)
 // - content - The content to copy to clipboard. Must be null terminated.
 // Return Value:
 // - True if handled successfully. False otherwise.
-bool AdaptDispatch::SetClipboard(const std::wstring_view content)
+bool AdaptDispatch::SetClipboard(const wil::zwstring_view content)
 {
     // Return false to forward the operation to the hosting terminal,
     // since ConPTY can't handle this itself.
diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp
index 9285d1126b7..36bb0312145 100644
--- a/src/terminal/adapter/adaptDispatch.hpp
+++ b/src/terminal/adapter/adaptDispatch.hpp
@@ -120,7 +120,7 @@ namespace Microsoft::Console::VirtualTerminal
         bool SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) override; // DECSCUSR
         bool SetCursorColor(const COLORREF cursorColor) override;
 
-        bool SetClipboard(const std::wstring_view content) override; // OSCSetClipboard
+        bool SetClipboard(const wil::zwstring_view content) override; // OSCSetClipboard
 
         bool SetColorTableEntry(const size_t tableIndex,
                                 const DWORD color) override; // OSCColorTable
diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp
index e2b8f298329..82bb4f21320 100644
--- a/src/terminal/adapter/termDispatch.hpp
+++ b/src/terminal/adapter/termDispatch.hpp
@@ -116,7 +116,7 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons
     bool SetCursorStyle(const DispatchTypes::CursorStyle /*cursorStyle*/) override { return false; } // DECSCUSR
     bool SetCursorColor(const COLORREF /*color*/) override { return false; } // OSCSetCursorColor, OSCResetCursorColor
 
-    bool SetClipboard(std::wstring_view /*content*/) override { return false; } // OscSetClipboard
+    bool SetClipboard(wil::zwstring_view /*content*/) override { return false; } // OscSetClipboard
 
     // DTTERM_WindowManipulation
     bool WindowManipulation(const DispatchTypes::WindowManipulationType /*function*/,
diff --git a/src/terminal/adapter/ut_adapter/adapterTest.cpp b/src/terminal/adapter/ut_adapter/adapterTest.cpp
index da8b7a35d3a..c8758c0f118 100644
--- a/src/terminal/adapter/ut_adapter/adapterTest.cpp
+++ b/src/terminal/adapter/ut_adapter/adapterTest.cpp
@@ -179,7 +179,7 @@ class TestGetSet final : public ITerminalApi
         return _expectedOutputCP;
     }
 
-    void CopyToClipboard(const std::wstring_view /*content*/)
+    void CopyToClipboard(const wil::zwstring_view /*content*/)
     {
         Log::Comment(L"CopyToClipboard MOCK called...");
     }
diff --git a/src/terminal/parser/ut_parser/OutputEngineTest.cpp b/src/terminal/parser/ut_parser/OutputEngineTest.cpp
index 9409f064080..f19ad423fbc 100644
--- a/src/terminal/parser/ut_parser/OutputEngineTest.cpp
+++ b/src/terminal/parser/ut_parser/OutputEngineTest.cpp
@@ -1453,9 +1453,9 @@ class StatefulDispatch final : public TermDispatch
         return true;
     }
 
-    bool SetClipboard(std::wstring_view content) noexcept override
+    bool SetClipboard(wil::zwstring_view content) noexcept override
     {
-        _copyContent = { content.begin(), content.end() };
+        _copyContent = content;
         return true;
     }
 


Test patch: