Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic support for WinRT asynchronous methods #465

Merged
merged 31 commits into from
Dec 31, 2022
Merged

Add basic support for WinRT asynchronous methods #465

merged 31 commits into from
Dec 31, 2022

Conversation

halildurmus
Copy link
Owner

@halildurmus halildurmus commented May 31, 2022

Fixes #39
Fixes #97

Adds support for WinRT asynchronous methods that return IAsyncAction or IAsyncOperation delegates. This is achieved by polling their status property every 10 milliseconds (I don't have a strong opinion on what this value should be) until it completes.

The other WinRT projections use the completed callback but we can't use that at the moment as async callbacks are not supported yet. This also prevents us from adding support for the asynchronous methods that return IAsyncActionWithProgress and IAsyncOperationWithProgress delegates (they report progress updates to callers through their progress callback).

Furthermore, I added IInitializeWithWindow interface and a wrapper for it (in winrt_com_interop_helpers.dart). This is necessary for APIs that depend on CoreWindow (Display WinRT UI objects that depend on CoreWindow explains this).

Also added the BasicProperties class and partially generated the StorageFile APIs (I'll fully generate them later as StorageFile has so many dependencies).

@halildurmus halildurmus changed the title [WIP] Support WinRT asynchronous APIs Add basic support for WinRT asynchronous methods Nov 28, 2022
@halildurmus halildurmus added feature A new feature or request winrt package: generator Issue with package:generator labels Nov 28, 2022
@halildurmus halildurmus marked this pull request as ready for review December 25, 2022 12:43
@timsneath
Copy link
Contributor

Woah! Is this ready for review? That would be the best Christmas present!

@halildurmus
Copy link
Owner Author

Woah! Is this ready for review? That would be the best Christmas present!

Yeah, I think this is finally ready for review :).

import 'package:win32/winrt.dart';

void main() async {
winrtInitialize();
final pIndex = calloc<Uint32>();

final picker = FileOpenPicker()
..suggestedStartLocation = PickerLocationId.desktop
Copy link
Contributor

@timsneath timsneath Dec 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why, but neither the suggestedStartLocation nor the viewMode property appear to be working on my machine. I've tried changing them to various other values, but they don't seem to affect the presented dialog box. Can you replicate?

Copy link
Owner Author

@halildurmus halildurmus Dec 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FileOpenPicker.SuggestedStartLocation Property states:

The SuggestedStartLocation is not always used as the start location for the file picker. To give the user a sense of consistency, the file picker remembers the last location that the user navigated to and will generally start at that location.

As for the viewMode property, I can't get it to work either. I'm installing Visual Studio right now. I'll try this example in a UWP app to see if this works properly there.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, it doesn't work in a UWP app either.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very strange. Investigating here too...

/// [target] must be a WinRT object that implements the
/// `IInitializeWithWindow` interface (e.g. `FileOpenPicker`).
///
/// [hwnd] represents the handle of the window to be used as the owner window.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if there are only specific types of HWND that are valid. I used GetActiveWindow() (which I would have thought would be the natural choice), and got an error: Error 0x80070578: Invalid window handle., which suggests that there's some specific criteria beyond being a valid HWND. I wasn't able to find documentation that answered this beyond this article.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if there are only specific types of HWND that are valid. I used GetActiveWindow() (which I would have thought would be the natural choice), and got an error: Error 0x80070578: Invalid window handle., which suggests that there's some specific criteria beyond being a valid HWND. I wasn't able to find documentation that answered this beyond this article.

I don't know. I found GetConsoleWindow() and GetShellWindow() by trial and error.

I just noticed that GetForegroundWindow() works for both console and Flutter apps (yay!). I wonder, should I make the necessary changes so that we use GetForegroundWindow() everywhere?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetForegroundWindow() is good, but it's not perfect -- for example, if there's another window from another process that has gained focus, it will become the parent for the file picker. That's why I'm a bit bemused that GetActiveWindow() isn't working here, since that means "the current window from the current process". (More here: https://devblogs.microsoft.com/oldnewthing/20081006-00/?p=20643)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. It was too good to be true anyway :).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to explain it:
https://devblogs.microsoft.com/oldnewthing/20190412-00/?p=102413

(TL;DR Not every window has a CoreWindow associated with it. We ought to figure out how to do IInitializeWithWindow from Dart).

Copy link
Contributor

@timsneath timsneath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some general comments above. Hopefully helpful!

Copy link
Contributor

@timsneath timsneath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's probably a little more iteration to be done on the example, but I think we're good to merge this as a baseline. This is awesome work, @halildurmus. I don't think I could have gotten there myself. Thank you so much!

@halildurmus
Copy link
Owner Author

There's probably a little more iteration to be done on the example, but I think we're good to merge this as a baseline. This is awesome work, @halildurmus. I don't think I could have gotten there myself. Thank you so much!

Thank you. Let's do this 🎉.

@halildurmus halildurmus merged commit 3f6140e into halildurmus:main Dec 31, 2022
@halildurmus halildurmus deleted the winrt-async branch December 31, 2022 20:22
@clarkezone
Copy link

Awesome would love to give this a try!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature A new feature or request package: generator Issue with package:generator
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Figure out async calls to WinRT Add WinRT FileOpenPicker
3 participants