SharpShade
SharpShade

Reputation: 2183

TaskDialog fires exception: comctl32.dll in version 6 required

I´m developing a modern WPF application. I want to use the TaskDialog, but I always get the common error:

TaskDialog feature needs to load version 6 of comctl32.dll but a different version is current loaded in memory.

I tried to add a manifest (which already contains the required dependency for the right comctl32.dll) and set it as default manifest in the project properties.

It still throws this exception :-/

My application is built like this: It´s a startup application (normal Windows application, non-wpf). It only has the "Program.cs" which is the entry point. There it load´s dynamically the real application (which is a library, not a WPF app project). It invokes it´s startup method which starts the application.

Works great, but I always get this exception. I guess it´s because of this startup-system ... but what would be a possible workaround to fix it?

Thanks a lot :)

R

Upvotes: 7

Views: 3902

Answers (3)

Greg
Greg

Reputation: 37

I have found that if you run with permission "RequireAdministrator" it throws the exception, but does not throw exception if permission "AsInvoker". Just my observation. If your app requires administrator privileges then I am stumped

Upvotes: 0

Guildenstern70
Guildenstern70

Reputation: 1859

Run the *.exe version of your program, and not the one for Visual Studio *.vshost.exe

To do so in Visual Studio, disable the flag in "Debug / Enable Debuggers / Enable the Visual Studio Hosting Process"

Upvotes: 3

Robpol86
Robpol86

Reputation: 1631

Maybe my solution will help you.

My C# "application" is a class library/dll used as a CustomAction for WIX. I wanted a TaskDialog instead of MessageBox but I ran into the same exception as you, and manifest files don't work for C# class libraries as far as I know. I had to use a combination of things to get my code to load the right version of comctl32.dll.

I just got it working so my code is a little messy and fatty.

Sources:

  1. http://truecheaters.com/f51/%5Bc-%5D-taskdialog-9368.html
  2. http://support.microsoft.com/kb/830033

1) Include the EnableThemingInScope class as-is from the second link above.

2) Include this modified TaskDialog enums/class:

[Flags]
public enum TaskDialogButtons {
    OK = 0x0001,
    Cancel = 0x0008,
    Yes = 0x0002,
    No = 0x0004,
    Retry = 0x0010,
    Close = 0x0020
}

public enum TaskDialogIcon {
    Information = UInt16.MaxValue - 2,
    Warning = UInt16.MaxValue,
    Stop = UInt16.MaxValue - 1,
    Question = 0,
    SecurityWarning = UInt16.MaxValue - 5,
    SecurityError = UInt16.MaxValue - 6,
    SecuritySuccess = UInt16.MaxValue - 7,
    SecurityShield = UInt16.MaxValue - 3,
    SecurityShieldBlue = UInt16.MaxValue - 4,
    SecurityShieldGray = UInt16.MaxValue - 8
}

public enum TaskDialogResult {
    None,
    OK,
    Cancel,
    Yes,
    No,
    Retry,
    Close
}

public class StatusDialog {
    #region API
    [DllImport( "comctl32.dll", CharSet = CharSet.Unicode )]
    public static extern int TaskDialog( IntPtr hWndParent, IntPtr hInstance, string pszWindowTitle, string pszMainInstruction, string pszContent, int dwCommonButtons, IntPtr pszIzon, out int pnButton );
    #endregion

    #region Modal
    public static TaskDialogResult Show( IWin32Window owner, string text ) {
        return Show( owner, text, null, null, TaskDialogButtons.OK );
    }

    public static TaskDialogResult Show( IWin32Window owner, string text, string instruction ) {
        return Show( owner, text, instruction, null, TaskDialogButtons.OK, 0 );
    }

    public static TaskDialogResult Show( IWin32Window owner, string text, string instruction, string caption ) {
        return Show( owner, text, instruction, caption, TaskDialogButtons.OK, 0 );
    }

    public static TaskDialogResult Show( IWin32Window owner, string text, string instruction, string caption, TaskDialogButtons buttons ) {
        return Show( owner, text, instruction, caption, buttons, 0 );
    }

    public static TaskDialogResult Show( IWin32Window owner, string text, string instruction, string caption, TaskDialogButtons buttons, TaskDialogIcon icon ) {
        return ShowInternal( owner.Handle, text, instruction, caption, buttons, icon );
    }
    #endregion

    #region Non-Modal
    public static TaskDialogResult Show( string text ) {
        return Show( text, null, null, TaskDialogButtons.OK );
    }

    public static TaskDialogResult Show( string text, string instruction ) {
        return Show( text, instruction, null, TaskDialogButtons.OK, 0 );
    }

    public static TaskDialogResult Show( string text, string instruction, string caption ) {
        return Show( text, instruction, caption, TaskDialogButtons.OK, 0 );
    }

    public static TaskDialogResult Show( string text, string instruction, string caption, TaskDialogButtons buttons ) {
        return Show( text, instruction, caption, buttons, 0 );
    }

    public static TaskDialogResult Show( string text, string instruction, string caption, TaskDialogButtons buttons, TaskDialogIcon icon ) {
        return ShowInternal( IntPtr.Zero, text, instruction, caption, buttons, icon );
    }
    #endregion

    #region Core Implementation
    private static TaskDialogResult ShowInternal( IntPtr owner, string text, string instruction, string caption, TaskDialogButtons buttons, TaskDialogIcon icon ) {
        int p;
        using ( new EnableThemingInScope( true ) ) {
            int resss = TaskDialog( owner, IntPtr.Zero, caption, instruction, text, (int) buttons, new IntPtr( (int) icon ), out p );
            if ( resss != 0 )
                throw new InvalidOperationException( "Something weird has happened." + resss.ToString() );
        }

        switch ( p ) {
            case 1:
                return TaskDialogResult.OK;
            case 2:
                return TaskDialogResult.Cancel;
            case 4:
                return TaskDialogResult.Retry;
            case 6:
                return TaskDialogResult.Yes;
            case 7:
                return TaskDialogResult.No;
            case 8:
                return TaskDialogResult.Close;
            default:
                return TaskDialogResult.None;
        }
    }
    #endregion
}

3. To call it, simply:

try {
    StatusDialog.Show( "About to test this...", "Heading I won't use.", "Dialog Title", TaskDialogButtons.OK );
} catch ( Exception e ) {
    MessageBox.Show( e.ToString(), "Error Found", MessageBoxButtons.OK );
}

4. Result:

enter image description here

Upvotes: 3

Related Questions