Gábor Gábor - 13 days ago 10
C# Question

IProgressDialog to start immediately

I use the

IProgressDialog
interface as per normal, everything works all right but the progress dialog only appears after a few seconds when it decides that the operation is indeed lengthy. Although this is nowhere documented, it seems to be intended behavior and not bad in many cases. However, in this particular application I'd need to display it immediately.

I found a single reference on the whole wide web to acknowledge this and to suggest a workaround. However, maybe because there were quite a few new Windows versions during that nine years, it doesn't seem to work today:

IProgressDialog dialog;
dialog.StartProgressDialog(owner, null, flags, IntPtr.Zero);
...
IntPtr DialogHWnd;
((IOleWindow)dialog).GetWindow(out DialogHWnd);
SendMessage(DialogHWnd, WM_TIMER, new IntPtr(1), IntPtr.Zero);


The window handle is OK, I checked it, there is no error, just there is no change in behavior. The dialog only appears after a few seconds.

Does anybody have a suggestion short of re-creating the same dialog and functionality in C# again? Not impossible, of course, but the stock dialog has nice features like animation and canceling behavior, in addition to being very familiar to users.

Answer

Call dialog.Timer(PDTIMER_RESUME, null) immediately before or after StartProgressDialog. Here is a minimal sample:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {

[Flags]
public enum IPD_Flags: uint {
    Normal = 0x00000000,
    Modal = 0x00000001,
    AutoTime = 0x00000002,
    NoTime = 0x00000004,
    NoMinimize = 0x00000008,
    NoProgressBar = 0x00000010 
}

[Flags]
public enum IPDTIMER_Flags: uint {
    Reset = 0x00000001,
    Pause = 0x00000002,
    Resume = 0x00000003
}

[ComImport]
[Guid("F8383852-FCD3-11d1-A6B9-006097DF5BD4")]
internal class ProgressDialog {
}

[ComImport]
[Guid("EBBC7C04-315E-11d2-B62F-006097DF5BD4")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IProgressDialog {

    [PreserveSig]
    void StartProgressDialog(IntPtr hwndParent
        , [MarshalAs(UnmanagedType.IUnknown)] object  punkEnableModless
        , uint dwFlags
        , IntPtr pvResevered);

    [PreserveSig]
    void StopProgressDialog();

    [PreserveSig]
    void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pwzTitle);

    [PreserveSig]
    void SetAnimation(IntPtr hInstAnimation, ushort idAnimation);

    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Bool)]
    bool HasUserCancelled();

    [PreserveSig]
    void SetProgress(uint dwCompleted, uint dwTotal);

    [PreserveSig]
    void SetProgress64(ulong ullCompleted, ulong ullTotal );

    [PreserveSig]
    void SetLine(uint dwLineNum
        , [MarshalAs(UnmanagedType.LPWStr)] string pwzString
        , [MarshalAs(UnmanagedType.VariantBool)] bool fCompactPath
        , IntPtr pvResevered);

    [PreserveSig]
    void SetCancelMsg([MarshalAs(UnmanagedType.LPWStr)]string pwzCancelMsg, object pvResevered);

    [PreserveSig]
    void Timer(uint dwTimerAction, object pvResevered);

}


public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) {
        ProgressDialog progressDialog = new ProgressDialog();
        IProgressDialog iProgressDialog = (IProgressDialog)progressDialog;

        iProgressDialog.Timer((uint) IPDTIMER_Flags.Resume, null);
        iProgressDialog.StartProgressDialog(this.Handle
            , null
            , (uint)(IPD_Flags.Normal | IPD_Flags.NoMinimize)
            , IntPtr.Zero);
    }
}

}