Создание индикатора выполнения, который работает на другом потоке при хранении вычисления в основном потоке

Если Вы обеспокоены нападениями на XSS, кодирование Ваших выходных строк к HTML является решением. Если Вы не забываете кодировать каждый выходной символ к формату HTML, нет никакого способа выполнить успешное нападение XSS.

Читать дальше пользовательские данные Очистки: Как и где сделать это

5
задан Community 23 May 2017 в 12:13
поделиться

3 ответа

Получение окна прогресса, постоянно отображаемого поверх (мертвой) формы, является сложным требованием. Обычно это выполняется с помощью перегрузки Form.Show (владелец). В вашем случае это вызывает проблемы, WF не оценит принадлежность формы владельца другому потоку. Это можно обойти, вызвав P / вызов SetWindowLong () для установки владельца.

Но теперь возникает новая проблема: окно прогресса срывается вверх, как только оно пытается отправить сообщение своему владельцу. Как ни странно, эта проблема исчезает, когда вы используете Invoke () вместо BeginInvoke () для обновления хода выполнения. Типа, вы все еще можете решить проблему, наведя указатель мыши на границу отключенного владельца. На самом деле вам придется использовать TopMost для определения Z-порядка. Более реалистично, Windows просто не t поддерживать то, что вы пытаетесь сделать. Вы знаете настоящее исправление, оно находится в начале вашего вопроса.

Вот код для экспериментов. Предполагается, что ваша прогрессивная форма называется dlgProgress:

Imports System.Threading

Public Class ShowProgress
  Implements IDisposable
  Private Delegate Sub UpdateProgressDelegate(ByVal pct As Integer)
  Private mOwnerHandle As IntPtr
  Private mOwnerRect As Rectangle
  Private mProgress As dlgProgress
  Private mInterlock As ManualResetEvent

  Public Sub New(ByVal owner As Form)
    Debug.Assert(owner.Created)
    mOwnerHandle = owner.Handle
    mOwnerRect = owner.Bounds
    mInterlock = New ManualResetEvent(False)
    Dim t As Thread = New Thread(AddressOf dlgStart)
    t.SetApartmentState(ApartmentState.STA)
    t.Start()
    mInterlock.WaitOne()
  End Sub

  Public Sub Dispose() Implements IDisposable.Dispose
    mProgress.BeginInvoke(New MethodInvoker(AddressOf dlgClose))
  End Sub

  Public Sub UpdateProgress(ByVal pct As Integer)
    mProgress.Invoke(New UpdateProgressDelegate(AddressOf dlgUpdate), pct)
  End Sub

  Private Sub dlgStart()
    mProgress = New dlgProgress
    mProgress.StartPosition = FormStartPosition.Manual
    mProgress.ShowInTaskbar = False
    AddHandler mProgress.Load, AddressOf dlgLoad
    AddHandler mProgress.FormClosing, AddressOf dlgClosing
    EnableWindow(mOwnerHandle, False)
    SetWindowLong(mProgress.Handle, -8, mOwnerHandle)
    Application.Run(mProgress)
  End Sub

  Private Sub dlgLoad(ByVal sender As Object, ByVal e As EventArgs)
    mProgress.Location = New Point( _
      mOwnerRect.Left + (mOwnerRect.Width - mProgress.Width) \ 2, _
      mOwnerRect.Top + (mOwnerRect.Height - mProgress.Height) \ 2)
    mInterlock.Set()
  End Sub

  Private Sub dlgUpdate(ByVal pct As Integer)
    mProgress.ProgressBar1.Value = pct
  End Sub

  Private Sub dlgClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
    EnableWindow(mOwnerHandle, True)
  End Sub

  Private Sub dlgClose()
    mProgress.Close()
    mProgress = Nothing
  End Sub

  '--- P/Invoke
  Public Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As IntPtr) As IntPtr
    If IntPtr.Size = 4 Then
      Return SetWindowLongPtr32(hWnd, nIndex, dwNewLong)
    Else
      Return SetWindowLongPtr64(hWnd, nIndex, dwNewLong)
    End If
  End Function

  Private Declare Function EnableWindow Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal enabled As Boolean) As Boolean
  Private Declare Function SetWindowLongPtr32 Lib "user32.dll" Alias "SetWindowLongW" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As IntPtr) As IntPtr
  Private Declare Function SetWindowLongPtr64 Lib "user32.dll" Alias "SetWindowLongW" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As IntPtr) As IntPtr

End Class

Пример использования:

  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Using dlg As New ShowProgress(Me)
      For ix As Integer = 1 To 100
        dlg.UpdateProgress(ix)
        System.Threading.Thread.Sleep(50)
      Next
    End Using
  End Sub
6
ответ дан 14 December 2019 в 04:41
поделиться

Я знаю, что это немного грязно, но разве вы не можете просто выполнить работу в диалоговом окне ??

Я имею в виду что-то вроде

Dialog.MyShowDialog(callback);

и выполняйте всю работу в обратном вызове, а также обновление пользовательского интерфейса.

Таким образом, вы сохраните поведение ShowDialog, позволяя вызывать другой код.

1
ответ дан 14 December 2019 в 04:41
поделиться

Некоторое время назад я написал сообщение в блоге по этой теме (речь идет о формах всплеска, но идея та же). Код написан на C #, но я постараюсь преобразовать его, разместив здесь (скоро ...).

1
ответ дан 14 December 2019 в 04:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: