0

Achieved Goal:

I am considering using PowerShell to monitor the input video from a USB camera device in real-time.

Problem:

Problem 1: When using the await class to wait for the return value (__ComObject) of the .Net async function, the first call (InitializeAsync) passes, but an unknown error occurs on the second call (StartPreviewAsync).

Problem 2: If I proceed without waiting for the above StartPreviewAsync, a thread error occurs.

Error Messages:

Error 1:

Exception occurred while calling "Wait" with "0" arguments: "One or more errors occurred."

Error 2:

Exception occurred while calling ".ctor" with "0" arguments: "The application called an interface that was marshaled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))"

Additional Information:

Changed the execution of $ui.Content = [CaptureElement]::new() to be executed within the UI dispatcher invoke, but it had no effect.

# using namespace
using namespace System.Windows
using namespace Windows.Foundation
using namespace Windows.Media.Capture
using namespace Windows.UI.Xaml.Controls

# using dotnet
using assembly  PresentationFramework
using assembly  System.Runtime.WindowsRuntime

# import Runtime type [TypeName, AssemblyName, ContentType]
[Windows.Foundation.IAsyncAction,         Windows.Foundation,       ContentType=WindowsRuntime]
[Windows.Media.Capture.MediaCapture,      Windows.Media.Capture,    ContentType=WindowsRuntime]
[Windows.UI.Xaml.Controls.CaptureElement, Windows.UI.Xaml.Controls, ContentType=WindowsRuntime]

# init MediaCapture
$capture = [Mediacapture]::new()
[await]::Action($capture.InitializeAsync(), [object])

 # ui
$ui = [Window]::new()
$ui.Dispatcher.Invoke([Action]{
    $ui.Content = [CaptureElement]::new()
    $ui.Content.Source = $capture
    [await]::Action($capture.StartPreviewAsync(), [object])
})
$ui.ShowDialog()

# awaiter class
class await{
    static [object]Action([__ComObject]$async, [type]$type){
        $asTask  = [WindowsRuntimeSystemExtensions].GetMethod("AsTask", [IAsyncAction])
        $netTask = $asTask.Invoke($null, @($async))
        $netTask.Wait()
        return $netTask.Result
    }
}
5
  • RPC_E_WRONG_THREAD happens when you try to access a UI element from a background thread. When you await a task, the code can resume on any thread, not necessarily the one you originally awaited on. The way to get around this is to call the Task.ConfigureAwait function withe the boolean value true as the argument at the end. This tells the task to continue on the original thread. I've never done this in powershell but I am guess you can chain all of your xxxAsync() calls that way. e.g. [await]::Action($capture.InitializeAsync().ConfigureAwait(true), [object]) Commented Jun 11 at 20:48
  • Thank you for your response. Since ConfigureAwait is a member of Task, I changed the call from await.Action to the following, but encountered the same error on the second call (StartPreviewAsync) (Error 1). By the way, when I corrected it as you taught me, I got an error saying that ConfigureAwait does not exist in __ComObject. Commented Jun 12 at 2:08
  • class await{ static [object]Action([__ComObject]$async, [type]$type){ $asTaskGeneric = [WindowsRuntimeSystemExtensions].GetMethod("AsTask", [IAsyncAction]) $netTask = $asTaskGeneric.Invoke($null, @($async)) $netTask.ConfigureAwait($true) $netTask.Wait() return $netTask.Result } } Commented Jun 12 at 2:48
  • It is true. ConfigureAwait does not exist in class __ComObject. It exists in class Task (specifically, class System.Threading.Tasks.Task). But does $asTaskGeneric.Invoke return a Task object? Commented Jun 12 at 19:48
  • That's right! asTask.Invoke takes a __ComObject as an IAsyncAction and can convert that __ComObject into a Task. [WindowsRuntimeSystemExtensions]::AsTask(arg) has many overrides, but none that take a __ComObject. Therefore, by calling a function with an IAsyncAction argument and passing the __ComObject as an IAsyncAction, it works correctly. WindowsRuntimeSystemExtensions is a .Net class that converts the return value of a WinRT asynchronous function, which is a __ComObject, into an appropriate type that can be handled in .Net (restoring it to its original return type). Commented Jun 12 at 23:07

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.