Я использую диалог прогресса Win32 . Самое ужасное, что когда я звоню:
progressDialog.StopProgressDialog();
оно не исчезает. Он остается на экране до тех пор, пока пользователь не наведет на него курсор мыши - , а затем .
Вызов StopProgressDialog
возвращается сразу (т.е. это не синхронный вызов). я могу доказать это, делая вещи после того, как звонок вернулся:
private void button1_Click(object sender, EventArgs e)
{
//Force red background to prove we've started
this.BackColor = Color.Red;
this.Refresh();
//Start a progress dialog
IProgressDialog pd = (IProgressDialog)new ProgressDialog();
pd.StartProgressDialog(this.Handle, null, PROGDLG.Normal, IntPtr.Zero);
//The long running operation
System.Threading.Thread.Sleep(10000);
//Stop the progress dialog
pd.SetLine(1, "Stopping Progress Dialog", false, IntPtr.Zero);
pd.StopProgressDialog();
pd = null;
//Return form to normal color to prove we've stopped.
this.BackColor = SystemColors.Control;
this.Refresh();
}
Форма:
- начинает серый
- становится красным, чтобы показать, что мы смотрели
- возвращается к серому цвету, чтобы показать, что мы назвали stop
Итак, звонок на StopProgressDialog
вернулся, за исключением того, что диалог с прогрессом все еще сидит там, издевается надо мной, показывая сообщение:
Диалог остановки процесса
не появляется в течение 10 секунд
Кроме того, диалоговое окно прогресса не появляется на экране до тех пор, пока
System.Threading.Thread.Sleep(10000);
сон на десять секунд окончен.
Не ограничивается .NET WinForms
Тот же код также не работает в Delphi, который также является обёрткой объекта для окон Window:
procedure TForm1.Button1Click(Sender: TObject);
var
pd: IProgressDialog;
begin
Self.Color := clRed;
Self.Repaint;
pd := CoProgressDialog.Create;
pd.StartProgressDialog(Self.Handle, nil, PROGDLG_NORMAL, nil);
Sleep(10000);
pd.SetLine(1, StringToOleStr('Stopping Progress Dialog'), False, nil);
pd.StopProgressDialog;
pd := nil;
Self.Color := clBtnFace;
Self.Repaint;
end;
PreserveSig
В случае сбоя StopProgressDialog
возникнет исключение.
Большинство методов в IProgressDialog, переведенные в C # (или в Delphi), используют автоматический механизм компилятора для преобразования неудачных COM HRESULTS в исключение родного языка.
Другими словами, следующие две подписи вызовут исключение, если вызов COM вернул ошибку HRESULT (то есть значение меньше нуля):
//C#
void StopProgressDialog();
//Delphi
procedure StopProgressDialog; safecall;
Принимая во внимание, что следующее позволяет увидеть HRESULT и отреагировать самостоятельно:
//C#
[PreserveSig]
int StopProgressDialog();
//Delphi
function StopProgressDialog: HRESULT; stdcall;
HRESULT - это 32-битное значение. Если старший бит установлен (или значение отрицательное), это ошибка.
Я использую прежний синтаксис. Таким образом, если StopProgressDialog
возвращает ошибку, она будет автоматически преобразована в исключение языка.
Примечание: Просто для SaG я использовал синтаксис [PreserveSig]
, возвращенный HRESULT равен нулю;
MsgWait
Симптом похож на то, что Раймонд Чен однажды описал , что связано с неправильным использованием PeekMessage, за которым следует MsgWaitForMultipleObjects:
"Иногда моя программа зависает и
сообщает на одну запись меньше, чем это
должен. Я должен трясти мышью, чтобы
получить значение для обновления. Спустя некоторое время
дольше он отстает на два, потом
три ... "
Но это будет означать, что сбой происходит в IProgressDialog, поскольку он одинаково хорошо работает на CLR .NET WinForms и собственном коде Win32.