如何在 Powershell 中处理 WinRT IInputStream?
How can I handle WinRT IInputStream in Powershell?
我喜欢查看连接的蓝牙耳机的电池状态。使用脚本,我希望能够在我的 Win10 桌面上使用 Rainmeter.
之类的东西打印它
我正在使用 WinRT 命名空间成功找到并连接到我的蓝牙耳机,但要打开一个流并读取内容(例如电池状态),我必须处理一个接口。
到目前为止我得到的工作:
#Add Type WinRT so that we can make use of Universal Windows Platform (UWP)
Add-Type -AssemblyName System.Runtime.WindowsRuntime
#To deal with asynchronous functions/actions in WinRT we can use the following functions: Await and AwaitAction
#With thanks to Ben N. on https://superuser.com/questions/1341997/using-a-uwp-api-namespace-in-powershell
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function Await($WinRtTask, $ResultType) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
$netTask = $asTask.Invoke($null, @($WinRtTask))
$netTask.Wait(-1) | Out-Null
$netTask.Result
}
Function AwaitAction($WinRtAction) {
$asTask = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and !$_.IsGenericMethod })[0]
$netTask = $asTask.Invoke($null, @($WinRtAction))
$netTask.Wait(-1) | Out-Null
}
#Get the relevant DeviceId from $btDeviceAll(not shown here for brevity)
$SonyWH1000XM3id = 'Bluetooth#Bluetoothac:##:##:##:##:##-##:##:##:##:##:##'
#Get relevant btDevice by referencing the DeviceId.
$btDeviceClass = [Windows.Devices.Bluetooth.BluetoothDevice,Windows.Devices.Bluetooth,ContentType = WindowsRuntime]
$btDevice = Await ($btDeviceClass::FromIdAsync($SonyWH1000XM3id)) ([Windows.Devices.Bluetooth.BluetoothDevice])
#Choose the relevant $btRfcommServices.services[] from $btRfcommServices(not shown here for brevity, my sony headset has HFP handsfree policy available)
$btHFPServiceUUID = '0000111e-0000-1000-8000-00805f9b34fb'
$btHFPConnectionHostName = '##:##:##:##:##:##'
$btHFPConnectionServiceName = 'Bluetooth#Bluetoothac:##:##:##:##:##-##:##:##:##:##:###RFCOMM:00000000:{00001108-0000-1000-8000-00805f9b34fb}'
#Connect to the device with a StreamSocket
[Windows.Networking.HostName,Windows.Networking,ContentType = WindowsRuntime]
[Windows.Networking.Sockets.StreamSocket,Windows.Networking.Sockets,ContentType = WindowsRuntime]
$btHostName = [Windows.Networking.HostName]($btHFPConnectionHostName)
$btSocket = New-Object Windows.Networking.Sockets.StreamSocket
AwaitAction ($btSocket.ConnectAsync($btHostName,$btHFPConnectionServiceName))
现在,要获取实际数据,我需要使用 $btSocket.InputStream
Property 通过:
- 方法:
IInputStream.ReadAsync(IBuffer, UInt32, InputStreamOptions)
;或者
- class
DataReader(IInputStream)
.
不幸的是,.InputStream 是一个 IInputStream 接口,但 Powershell 看到一个 System.__ComObject,我不知道如何告诉 Powershell 它是什么。因此,使用 DataReader(IInputStream) 的第二种方法会产生错误。第一种方法,通过调用 ReadAsync 给我 Object of type 'System.__ComObject' cannot be converted to type 'Windows.Foundation.IAsyncAction'
when:
$InputStreamOptionPartial = [Windows.Storage.Streams.InputStreamOptions]::Partial
$btByte = New-Object Byte[] 1024
$btIBuffer = [System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions]::AsBuffer($btByte)
$bfSize = [UInt32]"1024"
$btReadAsync = [Windows.Storage.Streams.IInputStream].GetMethod('ReadAsync',[type[]]@('Windows.Storage.Streams.Buffer','UInt32','Windows.Storage.Streams.InputStreamOptions'))
AwaitAction ($btReadAsync.Invoke($btSocket.InputStream,@($btIBuffer,$bfSize,$InputStreamOptionPartial)))
顺便说一句:我也试过在 Powershell 的 C# 脚本中执行它,但我什至无法让 C# 脚本使用 WinRT 命名空间,只有 using system.io
等
有人可以向我解释(或输入)如何让 DataReader() 接受 StreamSocket.IInputStream 或从 ReadAsync 获得工作缓冲区吗?也欢迎使用替代脚本解决方案。谢谢。
根据 documentation,IInputStream.ReadAsync()
returns IAsyncOperationWithProgress<IBuffer,uint>
并且您正在尝试使用 AsTask(IAsyncAction)
.
这里是一个使用AsTask(IAsyncOperationWithProgress<IBuffer,uint>)
的例子:
https://gist.github.com/lselden/ab2e04fbac785e0644c4b562bf5e35cd
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? {
$_.Name -eq 'AsTask' -and
$_.GetParameters().Count -eq 1 -and
$_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperationWithProgress`2' })[0];
Function AwaitWithProgress($WinRtTask, $ResultType1, $ResultType2) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType1, $ResultType2)
$netTask = $asTask.Invoke($null, @($WinRtTask))
$netTask.Wait(-1) | Out-Null
}
然后您可以 运行 您的调用方法如下:
AwaitWithProgress ($btReadAsync.Invoke($btSocket.InputStream,@($btIBuffer,$bfSize,$InputStreamOptionPartial))) ([Windows.Storage.Streams.IBuffer]) ([UInt32])
我喜欢查看连接的蓝牙耳机的电池状态。使用脚本,我希望能够在我的 Win10 桌面上使用 Rainmeter.
之类的东西打印它我正在使用 WinRT 命名空间成功找到并连接到我的蓝牙耳机,但要打开一个流并读取内容(例如电池状态),我必须处理一个接口。
到目前为止我得到的工作:
#Add Type WinRT so that we can make use of Universal Windows Platform (UWP)
Add-Type -AssemblyName System.Runtime.WindowsRuntime
#To deal with asynchronous functions/actions in WinRT we can use the following functions: Await and AwaitAction
#With thanks to Ben N. on https://superuser.com/questions/1341997/using-a-uwp-api-namespace-in-powershell
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function Await($WinRtTask, $ResultType) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
$netTask = $asTask.Invoke($null, @($WinRtTask))
$netTask.Wait(-1) | Out-Null
$netTask.Result
}
Function AwaitAction($WinRtAction) {
$asTask = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and !$_.IsGenericMethod })[0]
$netTask = $asTask.Invoke($null, @($WinRtAction))
$netTask.Wait(-1) | Out-Null
}
#Get the relevant DeviceId from $btDeviceAll(not shown here for brevity)
$SonyWH1000XM3id = 'Bluetooth#Bluetoothac:##:##:##:##:##-##:##:##:##:##:##'
#Get relevant btDevice by referencing the DeviceId.
$btDeviceClass = [Windows.Devices.Bluetooth.BluetoothDevice,Windows.Devices.Bluetooth,ContentType = WindowsRuntime]
$btDevice = Await ($btDeviceClass::FromIdAsync($SonyWH1000XM3id)) ([Windows.Devices.Bluetooth.BluetoothDevice])
#Choose the relevant $btRfcommServices.services[] from $btRfcommServices(not shown here for brevity, my sony headset has HFP handsfree policy available)
$btHFPServiceUUID = '0000111e-0000-1000-8000-00805f9b34fb'
$btHFPConnectionHostName = '##:##:##:##:##:##'
$btHFPConnectionServiceName = 'Bluetooth#Bluetoothac:##:##:##:##:##-##:##:##:##:##:###RFCOMM:00000000:{00001108-0000-1000-8000-00805f9b34fb}'
#Connect to the device with a StreamSocket
[Windows.Networking.HostName,Windows.Networking,ContentType = WindowsRuntime]
[Windows.Networking.Sockets.StreamSocket,Windows.Networking.Sockets,ContentType = WindowsRuntime]
$btHostName = [Windows.Networking.HostName]($btHFPConnectionHostName)
$btSocket = New-Object Windows.Networking.Sockets.StreamSocket
AwaitAction ($btSocket.ConnectAsync($btHostName,$btHFPConnectionServiceName))
现在,要获取实际数据,我需要使用 $btSocket.InputStream
Property 通过:
- 方法:
IInputStream.ReadAsync(IBuffer, UInt32, InputStreamOptions)
;或者 - class
DataReader(IInputStream)
.
不幸的是,.InputStream 是一个 IInputStream 接口,但 Powershell 看到一个 System.__ComObject,我不知道如何告诉 Powershell 它是什么。因此,使用 DataReader(IInputStream) 的第二种方法会产生错误。第一种方法,通过调用 ReadAsync 给我 Object of type 'System.__ComObject' cannot be converted to type 'Windows.Foundation.IAsyncAction'
when:
$InputStreamOptionPartial = [Windows.Storage.Streams.InputStreamOptions]::Partial
$btByte = New-Object Byte[] 1024
$btIBuffer = [System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions]::AsBuffer($btByte)
$bfSize = [UInt32]"1024"
$btReadAsync = [Windows.Storage.Streams.IInputStream].GetMethod('ReadAsync',[type[]]@('Windows.Storage.Streams.Buffer','UInt32','Windows.Storage.Streams.InputStreamOptions'))
AwaitAction ($btReadAsync.Invoke($btSocket.InputStream,@($btIBuffer,$bfSize,$InputStreamOptionPartial)))
顺便说一句:我也试过在 Powershell 的 C# 脚本中执行它,但我什至无法让 C# 脚本使用 WinRT 命名空间,只有 using system.io
等
有人可以向我解释(或输入)如何让 DataReader() 接受 StreamSocket.IInputStream 或从 ReadAsync 获得工作缓冲区吗?也欢迎使用替代脚本解决方案。谢谢。
根据 documentation,IInputStream.ReadAsync()
returns IAsyncOperationWithProgress<IBuffer,uint>
并且您正在尝试使用 AsTask(IAsyncAction)
.
这里是一个使用AsTask(IAsyncOperationWithProgress<IBuffer,uint>)
的例子:
https://gist.github.com/lselden/ab2e04fbac785e0644c4b562bf5e35cd
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? {
$_.Name -eq 'AsTask' -and
$_.GetParameters().Count -eq 1 -and
$_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperationWithProgress`2' })[0];
Function AwaitWithProgress($WinRtTask, $ResultType1, $ResultType2) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType1, $ResultType2)
$netTask = $asTask.Invoke($null, @($WinRtTask))
$netTask.Wait(-1) | Out-Null
}
然后您可以 运行 您的调用方法如下:
AwaitWithProgress ($btReadAsync.Invoke($btSocket.InputStream,@($btIBuffer,$bfSize,$InputStreamOptionPartial))) ([Windows.Storage.Streams.IBuffer]) ([UInt32])