Почему мой обратный вызов отображает разные результаты в .NET и Powershell?

1

Я пытаюсь написать скрипт для отслеживания хода выполнения WIM - пока я использовал этот пример оболочки WimgAPI: https://managedwimgapi.codeplex.com/wikipage?title=Using%20the%20message%20callback %20functionality %20for %20recieving %20progress %20and %20Разный %20information & referringtitle= документация

Которое я превратил в Powershell:

Add-Type -Path "Microsoft.Wim.dll"

# Open a handle to the .wim file
$wimHandle = [Microsoft.Wim.WimgApi]::CreateFile("G:\sources\boot.wim", '
    [Microsoft.Wim.WimFileAccess]::Read,[Microsoft.Wim.WimCreationDisposition]::OpenExisting, '
    [Microsoft.Wim.WimCreateFileOptions]::None, [Microsoft.Wim.WimCompressionType]::None)

# Always set temporary path
[Microsoft.Wim.WimgApi]::SetTemporaryPath($wimHandle, $env:temp) | Out-Null

# Build & register a callback method for actions which are performed by WIMGAPI for this .wim file
$callback = [Microsoft.Wim.WimMessageCallback]{
    param (
        [Microsoft.Wim.WimMessageType] $messageType,
        [System.Object] $message,
        [System.Object] $userData
    )

    if($messageType -eq [Microsoft.Wim.WimMessageType]::Progress)
    {
        $progressMessage = ($message -as [Microsoft.Wim.WimMessageProgress])
        Write-Host "Percent Complete: $($progressMessage.PercentComplete)" 
    }

    return [Microsoft.Wim.WimMessageResult]::Success
}

[Microsoft.Wim.WimgApi]::RegisterMessageCallback($wimHandle, $callback) | Out-Null

try
{
    # Get a handle to the first image in the .wim file
    $imageHandle = [Microsoft.Wim.WimgAPI]::LoadImage($wimHandle, 1)
    # Apply the contents to C:\Apply
    [Microsoft.Wim.WimgApi]::ApplyImage($imageHandle, "C:\Apply", [Microsoft.Wim.WimApplyImageOptions]::None)
    Read-Host
}
catch
{
    Write-Host $_.Exception
}
finally
{
    [Microsoft.Wim.WimgApi]::UnregisterMessageCallback($wimHandle, $callback) | Out-Null
}

Код выполняется успешно, и WIM применяется, но, к сожалению, я вижу, что callback выполняется дважды, например:

Percent Complete: 0
Percent Complete: 100

Хотя при выполнении приложения С# я вижу каждое процентное значение от нуля до 100.

Я думаю, что это может иметь какое-то отношение к тому факту, что ApplyImage является блокирующим вызовом и, следовательно, может блокировать консоль от выполнения обратного вызова, хотя я не могу придумать никакого способа обойти это.

Любые мысли были бы весьма признательны. Благодарю!

Теги:
callback
powershell
unmanaged
managed

1 ответ

1
Лучший ответ

Я написал CmdLet в С#, который будет применять образ *.wim к местоположению и подтолкнул его к GitHub и создал пакет Nuget.

https://github.com/dennisroche/Microsoft.Wim.Powershell

Сначала я начал писать CmdLet, так как мне удалась быстрая демонстрация С#, которая записывала прогресс% в консоль и считала, что CmdLet может быть решением (раньше я не писал CmdLet).

При написании CmdLet я обнаружил, что PowerShell выбрасывал InvalidOperationException при попытке записи (например, Write-Host, Write-Progress). Глядя далее на MSDN, я нашел следующее:

Этот метод может быть вызван только из реализации способа обработки входного сигнала (BeginProcessing, ProcessRecord и EndProcessing) и только из этого потока. Если вызов выполняется извне этих реализаций или из другого потока, InvalidOperationException исключение InvalidOperationException.

Это объясняет, почему он не работал при вызове непосредственно в Powershell - обратный вызов был в другом потоке, и его нужно было вызвать обратно в потоке Pipeline Execution Thread. Хотя по некоторым причинам первые и последние события прогресса были в Pipeline Execution Thread, поэтому мы видели результат, который мы сделали.

Я нашел интересное решение для вызова сообщений о ходе обновления в AsyncOperationManager Pipeline Execution Thread, используя AsyncOperationManager, WindowsFormsSynchronizationContext и Application.DoEvents(). Если вы нашли этот ответ в этом сообщении об ошибке, посмотрите на код GitHub.

  • 1
    Хорошая работа, Денис! Спасибо за это, это действительно озадачило меня!
  • 0
    Спасибо @slashp. Я надеюсь, что вы найдете это полезным. Если вам интересно, я использую это решение как часть другого проекта - github.com/dennisroche/Repave
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню