Private/Await.ps1
|
# 1. Laad eerst de basis die nodig is voor WinRT Add-Type -AssemblyName "System.Runtime.WindowsRuntime" Add-Type -AssemblyName "PresentationFramework" Add-Type -AssemblyName "WindowsBase" # 2. Maak een lijst van de WinRT types die je nodig hebt [Windows.Devices.Geolocation.Geolocator, Windows.Devices.Geolocation, ContentType = WindowsRuntime] | Out-Null [Windows.Devices.Radios.Radio, Windows.System.Devices, ContentType = WindowsRuntime] | Out-Null [Windows.Devices.Radios.RadioState, Windows.System.Devices, ContentType = WindowsRuntime] | Out-Null [Windows.Devices.Radios.RadioAccessStatus, Windows.System.Devices, ContentType = WindowsRuntime] | Out-Null [Windows.Devices.WiFi.WiFiAdapter, Windows.Devices.Wifi, ContentType = WindowsRuntime] | Out-Null [Windows.Devices.WiFi.WiFiReconnectionKind, Windows.Devices.Wifi, ContentType = WindowsRuntime] | Out-Null [Windows.Devices.Enumeration.DeviceInformation, Windows.Devices.Enumeration, ContentType = WindowsRuntime] | Out-Null [Windows.Security.Credentials.PasswordCredential, Windows.Security.Credentials, ContentType = WindowsRuntime] | Out-Null [Windows.Foundation.IAsyncInfo, Windows.Foundation, ContentType = WindowsRuntime] | Out-Null [Windows.Foundation.IAsyncOperation``1, Windows.Foundation, ContentType = WindowsRuntime] | Out-Null [Windows.Networking.Connectivity.NetworkInformation, Windows.Networking.Connectivity, ContentType = WindowsRuntime] | Out-Null <#$WinRTTypes = @( "Windows.Devices.Geolocation.Geolocator, Windows.Devices.Geolocation", "Windows.Devices.Radios.Radio, Windows.System.Devices", "Windows.Devices.Radios.RadioState, Windows.System.Devices", "Windows.Devices.WiFi.WiFiAdapter, Windows.Devices.Wifi", "Windows.Devices.WiFi.WiFiReconnectionKind, Windows.Devices.Wifi", "Windows.Devices.Radios.RadioAccessStatus, Windows.System.Devices", "Windows.Devices.Enumeration.DeviceInformation, Windows.Devices.Enumeration", "Windows.Security.Credentials.PasswordCredential, Windows.Security.Credentials", "Windows.Networking.Connectivity.NetworkInformation, Windows.Networking.Connectivity", "Windows.Foundation.IAsyncInfo, Windows.Foundation", "Windows.Foundation.IAsyncOperation``1, Windows.Foundation" )#> # 3. Laad ze allemaal in één keer via de loop #foreach ($Type in $WinRTTypes) { # Dit forceert PowerShell om de WinRT metadata te laden # $RuntimeLoaded = ([Type]::GetType("$Type, ContentType=WindowsRuntime")) #| Out-Null # if ($null -eq $RuntimeLoaded.Name) { # Write-Warning "Kon WinRT type niet laden: $Type" # } #} <# #For LocationPermissions [Windows.Devices.Geolocation.Geolocator, Windows.Devices.Geolocation, ContentType = WindowsRuntime] | Out-Null #For Radio On Off [Windows.Devices.Radios.Radio, Windows.System.Devices, ContentType = WindowsRuntime] | Out-Null [Windows.Devices.Radios.RadioState, Windows.System.Devices, ContentType = WindowsRuntime] | Out-Null [Windows.Devices.Radios.RadioAccessStatus, Windows.System.Devices, ContentType = WindowsRuntime] | Out-Null #Wifi [Windows.Devices.WiFi.WiFiAdapter, Windows.Devices.Wifi, ContentType = WindowsRunTime] | Out-Null [Windows.Devices.WiFi.WiFiReconnectionKind, Windows.DEvices.Wifi, ContentType = WindowsRuntime] | Out-Null #Device [Windows.Devices.Enumeration.DeviceInformation, Windows.Devices.Enumeration, ContentType = WindowsRunTime] | Out-Null #password [Windows.Security.Credentials.PasswordCredential, Windows.Security.Credentials, ContentType = WindowsRunTime] | Out-Null #networkConnection [Windows.Networking.Connectivity.NetworkInformation, Windows.Networking.Connectivity, Contenttype = WindowsRuntime] | Out-Null #> $asTaskGeneric = [System.WindowsRuntimeSystemExtensions].GetMethods() | Where-Object { $_.Name -eq 'AsTask' #-and $_.GetParameters().Count -eq 1 } $asTaskOperation = $asTaskGeneric | Where-Object { $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' } $asTaskAction = $asTaskGeneric | Where-Object { $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncAction' } $asTaskOperationCancel = $asTaskGeneric | Where-Object { $_.GetParameters().Count -eq 2 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' -and $_.GetParameters()[1].ParameterType.Name -eq 'CancellationToken' } $asTaskActionCancel = $asTaskGeneric | Where-Object { $_.GetParameters().Count -eq 2 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncAction' -and $_.GetParameters()[1].ParameterType.Name -eq 'CancellationToken' } Function Await($WinRtTask, $ResultType, [int]$TimeoutMs = 10000, [string]$Activity, [int]$ParentId = 0) { process { # Forceer de timeout tussen 1000 en 60000 ms if ($TimeoutMs -lt 1000) { $TimeoutMs = 1000 } if ($TimeoutMs -gt 60000) { $TimeoutMs = 120000 } if ($ResultType) { $asTask = $asTaskOperation.MakeGenericMethod($ResultType) $NetTask = $asTask.Invoke($null, @($WinRtTask)) } else { $NetTask = $asTaskAction.Invoke($null, @($WinRtTask)) } if ($Activity) { $elapsed = 0 $interval = 500 while (-not ( $NetTask.IsCompleted -or ($elapsed -ge $TimeoutMs))) { # Bereken percentage op basis van de voortgang van de TIMEOUT $percent = [int](($elapsed / $TimeoutMs) * 100) Write-Progress -Activity $Activity ` -Status "Wachten op respons $($NetTask.IsCompleted)... ($($elapsed)ms / $($TimeoutMs)ms)" ` -PercentComplete $percent -ParentId $ParentId Start-Sleep -Milliseconds $interval $elapsed += $interval } } else { # Zonder naam blokkeren we gewoon voor de ingestelde tijd [Void]$NetTask.Wait($TimeoutMs) } # Resultaat afhandeling if ($NetTask.IsCompleted) { if ($ResultType) { return $NetTask.Result } return $true } else { Write-Error "De WinRT terminated after $($TimeoutMs)ms." return $null } } } #AwaitWithCancel with a Global Anker <- otherwise we get an error 0xc00000005 #wel still struggeling with connecting wit wps pushbutton some how it fails if you release lock ?! Function AwaitWithCancel { [CmdletBinding()] param( [Parameter(Mandatory = $true)]$WinRtTask, [type] $ResultType, [int] $TimeoutMs = 120000, [string] $Activity, [int] $ParentId ) Begin { # 1. Gebruik de script-scope om de variabelen 'vast te pinnen' voor het End-blok [System.Threading.CancellationTokenSource]$script:cts = New-Object System.Threading.CancellationTokenSource $script:timer = [System.Diagnostics.Stopwatch]::StartNew() # Gebruik de automatische hardware-stop timer $script:cts.CancelAfter($TimeoutMs) # De WinRT-methode selector (moet vooraf gedefinieerd zijn in je module) if ($ResultType) { [System.Reflection.MethodInfo]$script:Method = $asTaskOperationCancel.MakeGenericMethod($ResultType) } else { $script:Method = $asTaskActionCancel } #write-host ("Method:{0}" -f $script:Method.Gettype().Name) } Process { write-Debug ("ParentId in Parameters:{0}" -f $PSBoundParameters.ContainsKey("ParentId") ) if ($PSBoundParameters.ContainsKey("ParentId")) { $id = $ParentId + 1 } else { $Id = 0 } # Start de Task-bridge en koppel de Token $script:NetTask = $script:Method.Invoke($null, @($WinRtTask, $script:cts.Token)) Write-debug ("NetTask:" -f $script:NetTask.gettype().Name) try { # Hoofd-loop: Wacht op de hardware OF de automatische annulering while (-not ( $script:NetTask.IsCompleted -or $script:cts.Token.IsCancellationRequested -or ($script:NetTask.Status -eq 'RanToCompletion') )) { if ($script:NetTask.IsCompleted) { Write-Host "Connected" } if ($Activity) { $elapsed = $script:timer.ElapsedMilliseconds $percent = [Math]::Min(100, [int](($elapsed / $TimeoutMs) * 100)) if ($ParentId) { Write-Progress -id $Id -Activity $Activity -Status "Wachten op WinRT... ($($elapsed)ms)" -ParentId $parentId -PercentComplete $percent } else { Write-Progress -id $Id -Activity $Activity -Status "Wachten op WinRT... ($($elapsed)ms)" -PercentComplete $percent } } # Gebruik een korte sleep om de thread niet te blokkeren Start-Sleep -Milliseconds 200 } } catch { Write-Error "Fout in de WinRT-communicatie: $($_.Exception.Message)" } # 3. Resultaat veilig ophalen $FinalResult = $null Write-Debug ("{1} - Status:{0}" -f $script:NetTask.Status, $ResultType.Name) if ($script:NetTask.Status -eq 'WaitingForActivation') { $Script:cts.Token } While (-not ($Script:NetTask.IsCompleted) ) { Write-Debug ("{1} - Status:{0} NetTask:{2}" -f $script:NetTask.Status, $ResultType.Name, $Script:NetTask.IsCompleted) Start-Sleep -Milliseconds 100 } Write-Debug ("{1} - Status:{0} NetTask:{2}" -f $script:NetTask.Status, $ResultType.Name, $Script:NetTask.IsCompleted) if ($null -ne $script:NetTask -and $script:NetTask.Status -eq 'RanToCompletion') { $FinalResult = $script:NetTask.Result #$script:cts.Dispose() } # 4. Schoonmaken pas NA bevestiging van de hardware $script:timer.Stop() # De Dispose is nu veilig omdat de driver 'IsCompleted' is # if($Activity){ Write-Progress -Id $Id -Completed -Activity $Activity} return $FinalResult } End { $script:cts.Cancel() } } <#Function AwaitWithCancel { [CmdletBinding()] param( [Parameter(Mandatory = $true)] $WinRtTask, [type] $ResultType, [int] $TimeoutMs = 10000, [string] $ProgressBarName ) begin { if ($TimeoutMs -lt 1000) { $TimeoutMs = 1000 } if ($TimeoutMs -gt 120000) { $TimeoutMs = 120000 } # Gebruik script-scope zodat 'End' erbij kan $script:cts = New-Object System.Threading.CancellationTokenSource $script:timer = [System.Diagnostics.Stopwatch]::StartNew() $script:cts.CancelAfter($TimeoutMs) $script:method = if ($ResultType) { $asTaskOperationCancel.MakeGenericMethod($ResultType) } else { $asTaskActionCancel } } Process { try { # De taak MOET in de script-scope staan $script:NetTask = $script:method.Invoke($null, @($WinRtTask, $script:cts.Token)) $method.delay( ) while (-not $script:NetTask.IsCompleted) { if ($ProgressBarName) { $elapsed = $script:timer.ElapsedMilliseconds $percent = [Math]::Min(100, [int](($elapsed / $TimeoutMs) * 100)) Write-Progress -Activity $ProgressBarName -Status "Wachten op WinRT... ($elapsed ms)" -PercentComplete $percent } Start-Sleep -Milliseconds 200 } } catch { # Fouten vangen, maar NIET hier afsluiten } } end { # DE HARDWARE LANDING if ($null -ne $script:NetTask -and -not $script:NetTask.IsCompleted) { $script:cts.Cancel() $safetyLoop = 0 # Houd de terminal OPEN totdat de driver de scan staakt while (-not $script:NetTask.IsCompleted -and $safetyLoop -lt 5000) { [System.Threading.Thread]::Sleep(100) $safetyLoop += 100 } } # Resultaat ophalen VOORDAT we disposen $FinalResult = $null if ($script:NetTask.Status -eq 'RanToCompletion') { $FinalResult = $script:NetTask.Result } # Alles opruimen $script:timer.Stop() $script:cts.Dispose() #Write-Progress -Activity $ProgressBarName -Completed return $FinalResult } }#> |