Click here to Skip to main content
Click here to Skip to main content

IProgressDialog .NET

, 23 Jan 2005
Rate this:
Please Sign up or sign in to vote.
A .NET wrapper for IProgressDialog interface and a COM object to allow use of the standard Windows progress dialog with AVI animation and built-in time remaining calculation.

Introduction

The reason for this article is to show a "pure" .NET wrapper for IProgressDialog [^] unleashed by sytelus in his Using Windows Explorer Progress Dialog In Your Application article.

Whilst the original article is quite good and I liked the idea greatly, I have found it a bit too "slow and heavy" with .tlb imports. I was also unable to find other articles/examples of implementation for .NET, so I decided to see if I can do it myself.

So here is what I have come up with.

Declaration of the Interface and COM for .NET

To start with, I've searched MSDN, Google and its groups for some clues about the interface. I've worked out that I need C# version of:

IProgressDialog * ppd;
CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, 
                                IID_IProgressDialog, (void **)&ppd);

After some Googling, I have come across an article at MSDN - COM Interop Part 1: C# Client Tutorial [^], which got me going:

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

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

where respective GUIDs are CLSID_ProgressDialog and IID_IProgressDialog.

The next step was translating interface definition from C++ to C#. For those who are interested, it is defined in ShlObj.h.

To cut a long story short, it was done, and a test app was put together without any serious problems except one - problem with marshaling bool to BOOL and vice versa. As it turned out there are two sides to the problem - first that there are two different BOOL in C++ - 2 and 4 bytes in size, whilst bool is only 1 byte (I'm not entirely sure in numbers, and can't find the page where I've seen it). Secondly, there is a bug in VS.NET 2003.

I tried various marshaling without any luck until Wraith, suggested using [PreserveSig] attribute. Not surprisingly, it did work for HasUserCancelled() method, which was the most problematic one.

Wraith, also saved me some time by sharing with us the results of his research of LoadLibraryEx which allows loading up a DLL as resource without processing of DllMain().

.NET Wrapper

Methods

After the hurdles were overcome, it was a matter of wrapping them in some user-friendly manner (especially having MS providing an example along with the interface definition in ShlObj.h).

Instead of exposing all interface methods to the end-user (well, developer that is), I only expose three:

  • public void Start( ProgressOperationCallback callback )

    The callback function is the one which will be doing the work (i.e., file copying, data mining etc.) and reporting the progress done back to the progress dialog.

    This function shows a progress dialog, sets title, cancel message, and animation. Upon Complete reaching Total, it closes the dialog by calling Stop() function.

  • public void Stop()

    Stops processing and hides the dialog.

  • public void SetLine( IPD_Lines line, string text, bool compactPath )

    Sets text for a specified line.

Properties

All other interface's methods are substituted by the properties:

  • Animation

    Gets or sets an AVI clip that will run in the dialog box.

  • CancelMessage

    Gets or sets a message to be displayed if the user cancels the operation.

  • Complete

    Gets or sets the application-defined value that indicates what proportion of the operation has been completed at the time the method was called.

  • Complete64

    Gets or sets the application-defined value that indicates what proportion of the operation has been completed at the time the method was called.

  • Flags

    Gets or sets flags that control the operation of the progress dialog box.

  • Title

    Gets or sets the title of the progress dialog box.

  • Total

    Gets or sets application-defined value that specifies what value Complete will have when the operation is complete.

  • Total64

    Gets or sets application-defined value that specifies what value Complete will have when the operation is complete.

Events

I've decided to make only two events - OnUserCancelled and OnBeforeProgressUpdate.

  • OnBeforeProgressUpdate is fired just before the dialog is about to call the callback function, so the program can update text messages if required.
  • OnUserCancelled is fired when a user has clicked "Cancel" button.

Using the code

Using the .NET wrapper is pretty much straight forward (so I hope anyway):

WinProgressDialog pDialog;
private uint _max, _step = 0;

private void button1_Click(object sender, System.EventArgs e) {
    this.pDialog = new WinProgressDialog( this.Handle );

    if( this.pDialog != null ) {
        this.pDialog.Title            = "Hello world!";
        this.pDialog.CancelMessage    = "hold on a sec...";
        this.pDialog.Flags = 
            WinProgressDialog.IPD_Flags.Normal | 
            WinProgressDialog.IPD_Flags.Modal |
            WinProgressDialog.IPD_Flags.NoMinimize |
            WinProgressDialog.IPD_Flags.AutoTime
            ;
        this.pDialog.Animation = WinProgressDialog.IPD_Animations.FileMove;

        this.pDialog.Complete        = ( this._step = 0 );
        this.pDialog.Total            = ( this._max = DoCalc() );

        this.pDialog.OnUserCancelled += 
            new WinProgressDialog.UserCancelledHandler( 
                        pDialog_OnUserCancelled 
                        );
        this.pDialog.OnBeforeProgressUpdate += 
            new WinProgressDialog.BeforeProgressUpdateHandler( 
                        pDialog_OnBeforeProgressUpdate 
                        );

        WinProgressDialog.ProgressOperationCallback progressUpdate =
            new WinProgressDialog.ProgressOperationCallback( this.DoStep );

        this.pDialog.Start( progressUpdate );
    }

    this.pDialog.Dispose();
}

private uint DoCalc() {
    // pretend to do some calc 
    System.Threading.Thread.Sleep( 2000 );
    // get some biggish number
    Random rand = new Random();
    return (uint)rand.Next( 150, 500 );
}

private uint DoStep() {
    // pretend to do some calc
    System.Threading.Thread.Sleep( 250 );
    this._step += 13;
    return this._step;
}

Points of Interest

There are a few things that can/need be done, including a way for loading custom resource instead of hard-coded shell32.dll. Later, it can be transformed to a true .NET control with all fancy designer stuff >Smile | :) .

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Igor Velikorossov
Software Developer (Senior)
Australia Australia
No Biography provided

Comments and Discussions

 
QuestionHow Can I Disable/Make Invisible Cancel Button PinmemberMember 127316319-Jan-09 23:06 
AnswerRe: How Can I Disable/Make Invisible Cancel Button PinmemberIgor Velikorossov20-Jan-09 3:48 
AnswerRe: How Can I Disable/Make Invisible Cancel Button Pinmembergeorgi nastev27-Jan-11 3:52 
GeneralNice! Here is VB.net 2005 version PinmemberBrianLaF21-Sep-06 16:01 
GeneralCustom Cancel Event PinmemberAndrew Y27-Jan-06 0:10 
Questionhow can i use in a c# app? Pinmemberjabulino9-Jan-06 1:53 
using a dll? copying code?
 
i'm a novice, thanks in advance...
 

GeneralNice but... PinmemberNelson F27-Jul-05 15:33 
GeneralProblems with VB.NET PinsussOscar A. G.29-Jun-05 0:42 
GeneralRe: Problems with VB.NET PinmemberRussKie29-Jun-05 3:44 
GeneralNicely done. PinmemberWraith,24-Jan-05 0:21 
GeneralRe: Nicely done. PinmemberRussKie24-Jan-05 0:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 24 Jan 2005
Article Copyright 2005 by Igor Velikorossov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid