dart-windows / win32

Build Win32 apps with Dart!
https://win32.pub
BSD 3-Clause "New" or "Revised" License
735 stars 118 forks source link

Add more WASAPI functions, interfaces and constants #800

Closed SirusDoma closed 6 months ago

SirusDoma commented 6 months ago

Add more WASAPI functions, interfaces, and constants. Fix: https://github.com/dart-windows/win32/issues/513

SirusDoma commented 6 months ago

A bit side-tracked but after testing these API in some of my small projects, I ran into an issue when using IAudioCaptureClient. Quoting from MSDN docs:

When releasing an IAudioCaptureClient interface instance, the client must call the Release method of the instance from the same thread as the call to IAudioClient::GetService that created the object.

I couldn't find a way to do this in Flutter. Every time the code executes from a button click, the 2 different methods of the same object seem to run under a different native thread leading to segfault / silent crash. My temporary solution is to let this capture client pointer leaking to avoid the crash.. Which is far more than ideal.

Any ideas on how to do this? I reckon I could use a native thread via CreateThread and call the GetService and Release under the same thread, but that would be complicated to do.

halildurmus commented 6 months ago

A bit side-tracked but after testing these API in some of my small projects, I ran into an issue when using IAudioCaptureClient. Quoting from MSDN docs:

When releasing an IAudioCaptureClient interface instance, the client must call the Release method of the instance from the same thread as the call to IAudioClient::GetService that created the object.

I couldn't find a way to do this in Flutter. Every time the code executes from a button click, the 2 different methods of the same object seem to run under a different native thread leading to segfault / silent crash. My temporary solution is to let this capture client pointer leaking to avoid the crash.. Which is far more than ideal.

Any ideas on how to do this? I reckon I could use a native thread via CreateThread and call the GetService and Release under the same thread, but that would be complicated to do.

Finalizers are attached to the COM objects in this package, which decrement the reference count of the object and then free its pointer (see here) when the objects go out of scope (as mentioned in the docs). Therefore, you should not free the pointers of these objects unless you're opting out of this behavior by calling the .detach() method of the object.

Edit: I'll review this PR in a few days, I'm a little busy at the moment.

SirusDoma commented 6 months ago

Finalizers are attached to the COM objects in this package, which decrement the reference count of the object and then free its pointer (see here) when the objects go out of scope (as mentioned in the docs). Therefore, you should not free the pointers of these objects unless you're opting out of this behavior by calling the .detach() method of the object.

Yes, I'm completely aware of what you wrote here. However, it doesn't matter if I let the finalizer run (e.g class that contains the IAudioCaptureClient / COM object went out of scope) or detach the pointer from the flutter object and freeing the object by myself: It always leads to segfault/crash because I think internally runs in a different native thread than the one it used to instantiate the object.

The problem isn't likely to be reproducible by example code where everything happens in a single method (eg. init -> render/capture -> object being freed due to out-of-scope at the same method), but it happens to me in a flutter project where init, capture and free/dispose happen within different methods (e.g initState() for init, capture after user-click and/or dispose when widget that contains the COM object no longer active / being rendered / out-of-scope).

Edit: I'll review this PR in a few days, I'm a little busy at the moment.

Please take your time, I'm using my local build for my project for now :)

halildurmus commented 6 months ago

The problem isn't likely to be reproducible by example code where everything happens in a single method (eg. init -> render/capture -> object being freed due to out-of-scope at the same method), but it happens to me in a flutter project where init, capture and free/dispose happen within different methods (e.g initState() for init, capture after user-click and/or dispose when widget that contains the COM object no longer active / being rendered / out-of-scope).

If you can share an example of this, I'd be happy to look into it.

SirusDoma commented 6 months ago

If you can share an example of this, I'd be happy to look into it.

Noted! I'll post a small reproducible flutter code/project later.

SirusDoma commented 6 months ago

Hi, I'm so sorry that I haven't updated much yet. I've been busy lately.
Anyway, about the issue about releasing the COM Object, I think the issue lies in my capture codes and not in the flutter or thread stuff. I'm not absolutely certain and have yet to confirm this. I'll post the update once I find something.

P.S I liked your commit Add static methods to PROPERTYKEY struct, not sure why you revert it.

halildurmus commented 6 months ago

P.S I liked your commit Add static methods to PROPERTYKEY struct, not sure why you revert it.

The commit caused some failures that I haven't been able to diagnose. I'll make another attempt tomorrow to identify and address the issues.

SirusDoma commented 6 months ago

Sorry to bring this up again. There's no problem with releasing the COM object. It appears I'm using Isolate incorrectly.
Anyway, when is this going to be released?