Conversation
Convert `WindowUtility` to partial and add file drag-and-drop handling. - Added `internal FileDropEvent` and `SetFileDropEnabled` to toggle `DROPFILES`/`COPYDATA`/`COPYGLOBALDATA` filters and call `DragAcceptFiles`. - Implemented `TryGetExternalDragPosition` to read external drag cursor position. - `WndProc` now handles `WM_DROPFILES` and forwards to `HandleFileDrop`. - HandleFileDrop enumerates dropped files (`DragQueryFile`/`DragQueryPoint`) and invokes `FileDropEvent`, then cleans up with `DragFinish`. - Added `NativeFileDrop` partial class with `P/Invoke` bindings and a `NativePoint` struct.
- Enable WinUI and native file drag-and-drop support for the Plugin Manager - Add drag enter/over/leave/drop handlers - Add a `DispatcherTimer` to track external drag position, and a visual drop indicator. - Wire `WindowUtility.FileDropEvent` on page load/unload and gate drops to the import area. - Extract import flow into an async `ImportPlugins` method and improve error handling around imports.
- PluginImporter: support importing `.zip` packages or `manifest.json`, validate filenames, copy assets to a staging directory and atomically move into place, protect against directory-traversal by resolving contained paths (`GetContainedPath`), and ensure cleanup on failure. Uses stream-based copy for assets. - PluginManagerPage: fixes drag indicator state, collects per-file failures instead of throwing `AggregateException`, logs errors, and shows a friendly dialog mapping common exceptions to readable messages.
bagusnl
left a comment
There was a problem hiding this comment.
Some changes are needed especially on the async void error handling and some localizations to user facing errors
| case WM_DROPFILES: | ||
| if (NativeFileDrop.TryHandleFileDrop((nint)wParam, | ||
| out string[]? files, | ||
| out POINTL dropPoint, | ||
| out Exception? ex)) | ||
| { | ||
| FileDropEvent?.Invoke(files, new PointInt32(dropPoint.x, dropPoint.y)); | ||
| } |
There was a problem hiding this comment.
Bug: The FileDropEvent is invoked with a nullable files array, but the OnNativeFileDrop handler and subsequent ImportPlugins call access it without a null check, risking a NullReferenceException.
Severity: HIGH
Suggested Fix
Add a null check for the files variable in WindowUtility.cs before invoking the FileDropEvent. For example: if (files != null) { FileDropEvent?.Invoke(files, ...); }. This ensures the event is only fired with a valid file list.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: CollapseLauncher/Classes/Helper/WindowUtility.cs#L694-L701
Potential issue: The `NativeFileDrop.TryHandleFileDrop` method can return a `null`
`files` array, as indicated by its `out string[]?` parameter. The `FileDropEvent` is
then invoked with this potentially null array. The event handler, `OnNativeFileDrop`,
expects a non-nullable `string[]` and passes it to the `ImportPlugins` method, which
immediately accesses `selectedFiles.Length` without any null validation. This will cause
a `NullReferenceException` if a file drop operation results in a `true` return from
`TryHandleFileDrop` but with a `null` file list. The exception occurs in an `async void`
handler, making it difficult to handle gracefully.
Also affects:
CollapseLauncher/XAMLs/MainApp/Pages/PluginManagerPage.xaml.cs:227~227
| try | ||
| { | ||
| _isWinUiFileDragActive = false; | ||
| SetImportDropIndicator(false); | ||
|
|
||
| if (!IsPointInDropArea(dropPoint)) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| await ImportPlugins(selectedFiles); |
There was a problem hiding this comment.
Bug: The OnNativeFileDrop handler for native file drops lacks a guard to prevent concurrent executions, creating a race condition if multiple drops occur quickly.
Severity: MEDIUM
Suggested Fix
In the OnNativeFileDrop method, add a check to ensure an import is not already in progress before calling ImportPlugins. For example: if (!ImportBoxButton.IsEnabled) return;.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: CollapseLauncher/XAMLs/MainApp/Pages/PluginManagerPage.xaml.cs#L172-L184
Potential issue: A race condition can occur if multiple file drop events are processed
in quick succession. The `OnNativeFileDrop` event handler, which is triggered by native
window messages, calls `await ImportPlugins` without checking if an import operation is
already in progress. While other UI-driven import paths check if
`ImportBoxButton.IsEnabled` is `false` to prevent concurrent operations, this native
drop handler lacks that guard. This can lead to multiple `ImportPlugins` tasks running
concurrently, causing unsafe concurrent modifications to the `PluginCollection`, which
is not thread-safe. This could result in collection corruption or duplicate entries.
neon-nyan
left a comment
There was a problem hiding this comment.
As per changes above. Tested the functionality and should be good for now.
Main Goal
Add drag-and-drop plugin importing to
PluginManagerPage, including support for dragging files from unelevated Windows Explorer into Collapse’s elevated process, while retaining the existing file-picker workflow.PR Status :
Changelog
[New] Added drag-and-drop plugin importing to
PluginManagerPage.ImportBoxButtonthroughAllowDrop="True"and the following XAML handlers:OnDragEnterImportBoxOnDragOverImportBoxOnDragLeaveImportBoxOnDropImportBoxOnDropImportBoxretrievesStorageFileobjects fromDragEventArgs.DataView.GetStorageItemsAsync()and converts them into file-system paths..zippackages andmanifest.jsonfiles are passed to the sameImportPluginsmethod used by the existing file picker.ImportPluginscallsPluginImporter.AutoGetImportFromPathfor each path and adds successfully importedPluginInfoobjects toPluginManagerPage.Context.PluginCollection.AggregateExceptionandErrorSender.SendException.ImportPluginsis running, preventing overlapping imports.[New] Added elevated-process file-drop support to
WindowUtility.requireAdministrator, which prevents normal Explorer drag events from reaching the WinUI drop target because Explorer usually runs at a lower integrity level.WindowUtility.SetFileDropEnabledto register the main window with the nativeDragAcceptFilesAPI.SetFileDropEnabledusesChangeWindowMessageFilterExto permit the native messages required for cross-integrity shell drops:WM_DROPFILESWM_COPYDATAWM_COPYGLOBALDATAWindowUtility.MainWndProcto processWM_DROPFILESand forward itsHDROPhandle toHandleFileDrop.HandleFileDropuses:DragQueryFileto retrieve every dropped path.DragQueryPointto retrieve the drop coordinates.DragFinishto release the nativeHDROPhandle.WindowUtility.FileDropEvent, which passes the collected paths and drop coordinates toPluginManagerPage.OnNativeFileDrop.PluginManagerPage.OnPluginManagerPageLoadedenables native file drops and subscribes toFileDropEvent.OnPluginManagerPageUnloadeddisables native file drops and removes the event subscription.OnNativeFileDropcallsIsPointInDropAreaso native drops are accepted only when they occur insideImportBoxButton.[Imp] Refactored the existing plugin import workflow.
OnClickImportButtonremains responsible for openingFileDialogNative.GetMultiFilePicker.ImportPlugins.OnClickImportButtonandOnDropImportBoxnow callImportPlugins, keeping validation, collection updates, partial-success handling, and error reporting consistent between both input methods..zipandmanifest.json.[Imp] Added drag-hover feedback for both WinUI and elevated Explorer drops.
Added the
ImportDropIndicatoroverlay directly above the plugin import panel.The overlay contains:
RectanglewithStrokeDashArray="1,2"andStrokeDashCap="Round".AccentColortheme resource.AccentFillColorDefaultBrush.Added a
ScalarTransitionwith a duration of 180 ms to fade the indicator in and out.SetImportDropIndicatortracks the current visibility state and changes the overlay opacity only when necessary.Standard WinUI drag events update
_isWinUiFileDragActiveand callSetImportDropIndicator.Native
WM_DROPFILESdoes not provide drag-enter or drag-leave notifications, soPluginManagerPageuses_fileDragIndicatorTimerto detect elevated Explorer hover state.OnFileDragIndicatorTimerTickcallsWindowUtility.TryGetExternalDragPositionevery 50 ms.TryGetExternalDragPositionuses:GetAsyncKeyStateto detect left- or right-button dragging.GetCursorPosto obtain the global pointer position.ScreenToClientto convert it into launcher client coordinates.GetForegroundWindowto avoid treating normal clicks inside Collapse as external drags.IsPointInDropAreacompares the native pointer coordinates against the transformed bounds ofImportBoxButton, including the current monitor scale factor.[Loc] Updated the English plugin-import instructions.
Templates
Changelog Prefixes