Win32: IProgressDialog will not disappear until you mouse over it.

Posted by Ian Boyd on Stack Overflow See other posts from Stack Overflow or by Ian Boyd
Published on 2008-12-18T15:51:31Z Indexed on 2010/04/17 10:03 UTC
Read the original article Hit count: 377

i'm using the Win32 progress dialog. The damnest thing is that when i call:

progressDialog.StopProgressDialog();

it doesn't disappear. It stays on screen until the user moves her mouse over it - then it suddenly disappers.

The call to StopProgressDialog returns right away (i.e. it's not a synchronous call). i can prove this by doing things after the call has returned:

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();
}

The form:

  • starts gray
  • turns red to show we've stared
  • turns back to gray color to show we've called stop

So the call to StopProgressDialog has returned, except the progress dialog is still sitting there, mocking me, showing the message:

Stopping Progress Dialog

alt text


Doesn't Appear for 10 seconds

Additionally, the progress dialog does not appear on screen until the

System.Threading.Thread.Sleep(10000);

ten second sleep is over.


Not limited to .NET WinForms

The same code also fails in Delphi, which is also an object wrapper around Window's windows:

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

An exception would be thrown if StopProgressDialog was failing.

Most of the methods in IProgressDialog, when translated into C# (or into Delphi), use the compiler's automatic mechanism of converting failed COM HRESULTS into a native language exception.

In other words the following two signatures will throw an exception if the COM call returned an error HRESULT (i.e. a value less than zero):

//C#
void StopProgressDialog();

//Delphi
procedure StopProgressDialog; safecall;

Whereas the following lets you see the HRESULT's and react yourself:

//C#
[PreserveSig]
int StopProgressDialog();

//Delphi
function StopProgressDialog: HRESULT; stdcall;

HRESULT is a 32-bit value. If the high-bit is set (or the value is negative) it is an error.

i am using the former syntax. So if StopProgressDialog is returning an error it will be automatically converted to a language exception.

Note: Just for SaG i used the [PreserveSig] syntax, the returned HRESULT is zero;


MsgWait?

The symptom is similar to what Raymond Chen described once, which has to do with the incorrect use of PeekMessage followed by MsgWaitForMultipleObjects:

"Sometimes my program gets stuck and reports one fewer record than it should. I have to jiggle the mouse to get the value to update. After a while longer, it falls two behind, then three..."

But that would mean that the failure is in IProgressDialog, since it fails equally well on CLR .NET WinForms and native Win32 code.

© Stack Overflow or respective owner

Related posts about winapi

Related posts about iprogressdialog