Skip to content

fix(share_plus): correct Windows share sheet data package setup - #3975

Open
MobileWeblink wants to merge 2 commits into
fluttercommunity:mainfrom
MobileWeblink:fix/share-plus-windows-share-sheet
Open

MobileWeblink wants to merge 2 commits into
fluttercommunity:mainfrom
MobileWeblink:fix/share-plus-windows-share-sheet

Conversation

@MobileWeblink

@MobileWeblink MobileWeblink commented Sep 17, 2026

Copy link
Copy Markdown

Description

On Windows the share sheet fails with "Try that again — We couldn't show you all the ways you could share", both when sharing files and when sharing text only. The DataPackage built by the plugin is rejected by Windows.

Several distinct problems in the Windows implementation contribute to this, each of which is enough to produce that error:

  • IStorageFile was reinterpret_cast to IStorageItem. The two interfaces are unrelated at the ABI level, so the collection handed to the DataPackage contained pointers with the wrong vtable. The interface is now obtained via QueryInterface.
  • The IStorageItem collection was a stack allocated Vector<>, while the DataPackage keeps a reference to it after the DataRequested handler has returned. It is now heap allocated with WRL::Make<> and owned by the plugin.
  • SetStorageItemsReadOnly was called unconditionally, so a text-only share advertised an empty file collection. It is now only called when there is at least one file.
  • An empty Title was set when sharing files without a title, subject or text. Windows rejects a package with an empty title, so the title now falls back to the subject, the text, the URI and finally the window title.
  • Files were resolved with a synchronous wait (GetFileFromPathAsync plus a SleepEx spin) inside the DataRequested handler, which runs on the UI thread with a short deadline. They are now resolved before ShowShareUIForWindow is called.
  • add_DataRequested was called on every share without ever removing the previous handler, and the registration token was overwritten. Handlers accumulated and all wrote to the DataPackage of every later request.

Additionally:

  • Plugin state is reset on every call, so paths, title, subject and text are no longer inherited from the previous share when the new call omits them.
  • Arguments are read with find instead of std::map::operator[], which was inserting null values for missing keys.
  • HRESULTs are checked and propagated to Dart as a method channel error, instead of always reporting success.
  • The IStorageFile reference returned by GetStorageFileFromPath is no longer leaked.
  • Utf16FromUtf8 no longer includes the terminating NUL in the converted std::wstring, which was embedding a NUL in the resulting HSTRINGs.

No Dart code is affected, so the existing tests are unchanged.

Testing

Verified on Windows 11 when sharing a single PDF file: before this change the share sheet showed "Try that again — We couldn't show you all the ways you could share", after it the sheet opens and lists the share targets.

Still to be verified:

  1. text only
  2. text and files together
  3. two consecutive shares without restarting the app
  4. a large file or a network path

Related Issues

Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I titled the PR using Conventional Commits.
  • I did not modify the CHANGELOG.md nor the plugin version in pubspec.yaml files.
  • All existing and new tests are passing.
  • The analyzer (flutter analyze) does not report any problems on my PR.

Breaking Change

  • Yes, this is a breaking change.
  • No, this is not a breaking change.

The Windows share sheet failed with "We couldn't show you all the ways
you could share" because the DataPackage handed to Windows was invalid.

Several issues contributed to this:

- IStorageFile was reinterpret_cast to IStorageItem. The two interfaces
  are unrelated at the ABI level, so the share target received a pointer
  with the wrong vtable. The interface is now obtained via QueryInterface.
- The IStorageItem collection was stack allocated, while the DataPackage
  keeps a reference to it after the DataRequested handler returns. It is
  now heap allocated and owned by the plugin.
- SetStorageItemsReadOnly was called unconditionally, so a text-only
  share advertised an empty file collection. It is now only called when
  there is at least one file.
- An empty Title was set when sharing files without a title, subject or
  text. Windows rejects such a package, so the title now falls back to
  the subject, the text, the URI and finally the window title.
- Files were resolved with a synchronous wait inside the DataRequested
  handler, which runs on the UI thread with a short deadline. They are
  now resolved before the share UI is shown.
- add_DataRequested was called on every share without ever removing the
  previous handler, leaving stale handlers writing to later packages.

Additionally, the plugin state is reset on every call so values are no
longer inherited from the previous share, HRESULTs are propagated to
Dart instead of always reporting success, the IStorageFile reference is
no longer leaked, and Utf16FromUtf8 no longer embeds a NUL terminator in
the converted string.
@MobileWeblink

Copy link
Copy Markdown
Author

Update on testing: I have now verified this on a real machine.

  • OS: Windows 11
  • Scenario: sharing a single PDF file
  • Before: the share sheet showed "Try that again — We couldn't show you all the ways you could share"
  • After: the share sheet opens correctly and lists the available share targets

The other scenarios from the description (text only, text and files together, two consecutive shares, large files and network paths) have not been verified yet.

@MobileWeblink

Copy link
Copy Markdown
Author

The formatting check was failing on packages/share_plus/share_plus/test/share_plus_windows_test.dart, which this PR does not otherwise touch: the file is already unformatted on main (reproducible on the base commit 13e1704), and the check only runs on pull requests, so it went unnoticed.

I pushed a separate commit applying dart format to that file so the check can pass. Happy to drop it into its own PR instead if you prefer to keep this one focused.

The file was not formatted according to the dart format version used by
CI, which made the formatting check report it. It is unrelated to the
Windows fix in this PR.
@MobileWeblink
MobileWeblink force-pushed the fix/share-plus-windows-share-sheet branch from da57a7d to 106bbec Compare September 17, 2026 09:52
@MobileWeblink

Copy link
Copy Markdown
Author

A note on the red checks, since most of them are not caused by this PR. The same five checks are currently failing on every open pull request (#3970, #3971, #3972), so they look like pre-existing breakage on main:

  • Check code formatting — besides the share_plus test file, the step reports packages/android_intent_plus/example/analysis_options.yaml, packages/connectivity_plus/connectivity_plus/example/analysis_options.yaml and packages/package_info_plus/package_info_plus/example/analysis_options.yaml as modified. Those are the analyzer: exclude: blocks that melos bootstrap injects, not something a contributor changed.
  • analyzeandroid_intent_plus reports 19 issues, all deprecated_member_use on LocalPlatform and FakePlatform.
  • windows_example_build / windows_integration_testexample/windows/runner/win32_window.cpp(179,3): error C2360: initialization of 'rect' is skipped by 'case' label. That is the Flutter runner template in the example, failing with the MSVC version on the runners. The share_plus plugin target itself compiles: the build reaches the runner without reporting any error from the plugin project.
  • Check pub.dev requirements — also failing on the other open PRs.

The one item that does belong to this PR is test/share_plus_windows_test.dart. My first attempt formatted it with a different dart format version than CI uses; I have now applied exactly the diff CI printed, so share_plus should drop off that list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant