mirror of
https://github.com/microsoft/terminal.git
synced 2026-02-13 13:45:27 +00:00
Fix missing paths when items dropped from archive (#14648)
Grab all paths from `DROPFILES` struct provided in drag event data `GetStorageItemsAsync()` only giving up to 16 items when items are dropped from any archives - When this occurs, we should look into `FileDrop` key for a stream of the [`DROPFILES struct`](https://learn.microsoft.com/en-us/windows/win32/shell/clipboard#cf_hdrop) - This struct contains a null-character delimited string of paths which we can just read out ## Validation Steps Performed * [X] Unit tests pass locally * [X] Drag and drop paths work for both archives and non-archives files, folders, shortcuts, etc. Closes #14628
This commit is contained in:
@@ -25,6 +25,7 @@ using namespace winrt::Windows::UI::ViewManagement;
|
||||
using namespace winrt::Windows::UI::Input;
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::ApplicationModel::DataTransfer;
|
||||
using namespace winrt::Windows::Storage::Streams;
|
||||
|
||||
// The minimum delay between updates to the scroll bar's values.
|
||||
// The updates are throttled to limit power usage.
|
||||
@@ -2526,17 +2527,58 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
if (items.Size() > 0)
|
||||
{
|
||||
std::wstring allPaths;
|
||||
for (auto item : items)
|
||||
std::vector<std::wstring> fullPaths;
|
||||
|
||||
// GH#14628: Workaround for GetStorageItemsAsync() only returning 16 items
|
||||
// at most when dragging and dropping from archives (zip, 7z, rar, etc.)
|
||||
if (items.Size() == 16 && e.DataView().Contains(winrt::hstring{ L"FileDrop" }))
|
||||
{
|
||||
auto fileDropData = co_await e.DataView().GetDataAsync(winrt::hstring{ L"FileDrop" });
|
||||
if (fileDropData != nullptr)
|
||||
{
|
||||
auto stream = fileDropData.as<IRandomAccessStream>();
|
||||
stream.Seek(0);
|
||||
|
||||
const uint32_t streamSize = gsl::narrow_cast<uint32_t>(stream.Size());
|
||||
const Buffer buf(streamSize);
|
||||
const auto buffer = co_await stream.ReadAsync(buf, streamSize, InputStreamOptions::None);
|
||||
|
||||
const HGLOBAL hGlobal = buffer.data();
|
||||
const auto count = DragQueryFileW(static_cast<HDROP>(hGlobal), 0xFFFFFFFF, nullptr, 0);
|
||||
fullPaths.reserve(count);
|
||||
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
std::wstring path;
|
||||
path.resize(wil::max_path_length);
|
||||
const auto charsCopied = DragQueryFileW(static_cast<HDROP>(hGlobal), i, path.data(), wil::max_path_length);
|
||||
|
||||
if (charsCopied > 0)
|
||||
{
|
||||
path.resize(charsCopied);
|
||||
fullPaths.emplace_back(std::move(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fullPaths.reserve(items.Size());
|
||||
for (const auto& item : items)
|
||||
{
|
||||
fullPaths.emplace_back(item.Path());
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring allPathsString;
|
||||
for (auto& fullPath : fullPaths)
|
||||
{
|
||||
// Join the paths with spaces
|
||||
if (!allPaths.empty())
|
||||
if (!allPathsString.empty())
|
||||
{
|
||||
allPaths += L" ";
|
||||
allPathsString += L" ";
|
||||
}
|
||||
|
||||
std::wstring fullPath{ item.Path() };
|
||||
|
||||
// Fix path for WSL
|
||||
// In the fullness of time, we should likely plumb this up
|
||||
// to the TerminalApp layer, and have it make the decision
|
||||
@@ -2591,10 +2633,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
fullPath += L"\"";
|
||||
}
|
||||
|
||||
allPaths += fullPath;
|
||||
allPathsString += fullPath;
|
||||
}
|
||||
|
||||
_core.PasteText(winrt::hstring{ allPaths });
|
||||
_core.PasteText(winrt::hstring{ allPathsString });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>dwrite.lib;dxgi.lib;d2d1.lib;d3d11.lib;shcore.lib;winmm.lib;pathcch.lib;propsys.lib;uiautomationcore.lib;Shlwapi.lib;ntdll.lib;user32.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>dwrite.lib;dxgi.lib;d2d1.lib;d3d11.lib;shcore.lib;winmm.lib;pathcch.lib;propsys.lib;uiautomationcore.lib;Shlwapi.lib;ntdll.lib;user32.lib;shell32.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<!--
|
||||
ControlLib contains a DllMain that we need to force the use of.
|
||||
If you don't have this, then you'll see an error like
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <winrt/Windows.ui.xaml.shapes.h>
|
||||
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/Windows.Storage.Streams.h>
|
||||
#include <winrt/Windows.UI.Xaml.Shapes.h>
|
||||
|
||||
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
|
||||
@@ -59,6 +60,7 @@
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hTerminalControlProvider);
|
||||
#include <telemetry/ProjectTelemetry.h>
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <ShlObj_core.h>
|
||||
#include <WinUser.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user