C#:调试器中的comctl32.dll版本6

时间:2009-09-12 14:33:14

标签: c# visual-studio-2008 winapi taskdialog comctl32

我正在使用WindowsAPICodePack for TaskDialog。当我尝试显示对话框时,它说它需要加载comctl32.dll的版本6。所以我在app.manifest中添加了第6版并尝试运行它。仍然没有运气。我去了Debug文件夹并运行没有Visual Studio的程序,它工作正常。我猜测Visual Studio没有使用清单文件......我想知道是否有办法让它做到这一点。

4 个答案:

答案 0 :(得分:10)

Robpol86,您的代码正在抛出SEHExceptions,因为ActivateActCtx和DeactivateActCtx的签名不正确。对于lpCookie,您必须使用UIntPtr代替uint

因此,EnableThemingInScope.cs的正确代码为:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Windows.Forms;

namespace Microsoft.WindowsAPICodePack.Dialogs
{
    /// http://support.microsoft.com/kb/830033
    /// <devdoc>
    ///     This class is intended to use with the C# 'using' statement in
    ///     to activate an activation context for turning on visual theming at
    ///     the beginning of a scope, and have it automatically deactivated
    ///     when the scope is exited.
    /// </devdoc>

    [SuppressUnmanagedCodeSecurity]
    internal class EnableThemingInScope : IDisposable
    {
        // Private data
        private UIntPtr cookie;
        private static ACTCTX enableThemingActivationContext;
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        private static IntPtr hActCtx;
        private static bool contextCreationSucceeded = false;

        public EnableThemingInScope(bool enable)
        {
            cookie = UIntPtr.Zero;
            if (enable && OSFeature.Feature.IsPresent(OSFeature.Themes))
            {
                if (EnsureActivateContextCreated())
                {
                    if (!ActivateActCtx(hActCtx, out cookie))
                    {
                        // Be sure cookie always zero if activation failed
                        cookie = UIntPtr.Zero;
                    }
                }
            }
        }

        ~EnableThemingInScope()
        {
            Dispose();
        }

        void IDisposable.Dispose()
        {
            Dispose();
            GC.SuppressFinalize(this);
        }

        private void Dispose()
        {
            if (cookie != UIntPtr.Zero)
            {
                try
                {
                    if (DeactivateActCtx(0, cookie))
                    {
                        // deactivation succeeded...
                        cookie = UIntPtr.Zero;
                    }
                }
                catch (SEHException)
                {
                    //Hopefully solved this exception
                }
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity")]
        private static bool EnsureActivateContextCreated()
        {
            lock (typeof(EnableThemingInScope))
            {
                if (!contextCreationSucceeded)
                {
                    // Pull manifest from the .NET Framework install
                    // directory

                    string assemblyLoc = null;

                    FileIOPermission fiop = new FileIOPermission(PermissionState.None);
                    fiop.AllFiles = FileIOPermissionAccess.PathDiscovery;
                    fiop.Assert();
                    try
                    {
                        assemblyLoc = typeof(Object).Assembly.Location;
                    }
                    finally
                    {
                        CodeAccessPermission.RevertAssert();
                    }

                    string manifestLoc = null;
                    string installDir = null;
                    if (assemblyLoc != null)
                    {
                        installDir = Path.GetDirectoryName(assemblyLoc);
                        const string manifestName = "XPThemes.manifest";
                        manifestLoc = Path.Combine(installDir, manifestName);
                    }

                    if (manifestLoc != null && installDir != null)
                    {
                        enableThemingActivationContext = new ACTCTX();
                        enableThemingActivationContext.cbSize = Marshal.SizeOf(typeof(ACTCTX));
                        enableThemingActivationContext.lpSource = manifestLoc;

                        // Set the lpAssemblyDirectory to the install
                        // directory to prevent Win32 Side by Side from
                        // looking for comctl32 in the application
                        // directory, which could cause a bogus dll to be
                        // placed there and open a security hole.
                        enableThemingActivationContext.lpAssemblyDirectory = installDir;
                        enableThemingActivationContext.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;

                        // Note this will fail gracefully if file specified
                        // by manifestLoc doesn't exist.
                        hActCtx = CreateActCtx(ref enableThemingActivationContext);
                        contextCreationSucceeded = (hActCtx != new IntPtr(-1));
                    }
                }

                // If we return false, we'll try again on the next call into
                // EnsureActivateContextCreated(), which is fine.
                return contextCreationSucceeded;
            }
        }

        // All the pinvoke goo...
        [DllImport("Kernel32.dll")]
        private extern static IntPtr CreateActCtx(ref ACTCTX actctx);
        [DllImport("Kernel32.dll")]
        private extern static bool ActivateActCtx(IntPtr hActCtx, out UIntPtr lpCookie);
        [DllImport("Kernel32.dll")]
        private extern static bool DeactivateActCtx(uint dwFlags, UIntPtr lpCookie);

        private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;

        private struct ACTCTX
        {
            public int cbSize;
            public uint dwFlags;
            public string lpSource;
            public ushort wProcessorArchitecture;
            public ushort wLangId;
            public string lpAssemblyDirectory;
            public string lpResourceName;
            public string lpApplicationName;
        }
    }
}

答案 1 :(得分:4)

我最近在使用CodePack中的TaskDialogDemo调试代码时遇到了这个问题。这就是我修复它的方式。使用它的问题是,如果我打开两个或三个对话框,它会抛出一个SEHException,我还没弄清楚如何解决。所以买家要小心。

添加 Core \ Interop \ TaskDialogs \ EnableThemingInScope.cs

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Windows.Forms;

namespace Microsoft.WindowsAPICodePack.Dialogs {
    /// http://support.microsoft.com/kb/830033
    /// <devdoc>
    ///     This class is intended to use with the C# 'using' statement in
    ///     to activate an activation context for turning on visual theming at
    ///     the beginning of a scope, and have it automatically deactivated
    ///     when the scope is exited.
    /// </devdoc>

    [SuppressUnmanagedCodeSecurity]
    internal class EnableThemingInScope : IDisposable {
        // Private data
        private uint cookie;
        private static ACTCTX enableThemingActivationContext;
        [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources" )]
        private static IntPtr hActCtx;
        private static bool contextCreationSucceeded = false;

        public EnableThemingInScope( bool enable ) {
            cookie = 0;
            if ( enable && OSFeature.Feature.IsPresent( OSFeature.Themes ) ) {
                if ( EnsureActivateContextCreated() ) {
                    if ( !ActivateActCtx( hActCtx, out cookie ) ) {
                        // Be sure cookie always zero if activation failed
                        cookie = 0;
                    }
                }
            }
        }

        ~EnableThemingInScope() {
            Dispose();
        }

        void IDisposable.Dispose() {
            Dispose();
            GC.SuppressFinalize( this );
        }

        private void Dispose() {
            if ( cookie != 0 ) {
                try {
                    if ( DeactivateActCtx( 0, cookie ) ) {
                        // deactivation succeeded...
                        cookie = 0;
                    }
                } catch ( SEHException ) {
                    // Robpol86: I don't know how to fix this!
                }
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity" )]
        private static bool EnsureActivateContextCreated() {
            lock ( typeof( EnableThemingInScope ) ) {
                if ( !contextCreationSucceeded ) {
                    // Pull manifest from the .NET Framework install
                    // directory

                    string assemblyLoc = null;

                    FileIOPermission fiop = new FileIOPermission( PermissionState.None );
                    fiop.AllFiles = FileIOPermissionAccess.PathDiscovery;
                    fiop.Assert();
                    try {
                        assemblyLoc = typeof( Object ).Assembly.Location;
                    } finally {
                        CodeAccessPermission.RevertAssert();
                    }

                    string manifestLoc = null;
                    string installDir = null;
                    if ( assemblyLoc != null ) {
                        installDir = Path.GetDirectoryName( assemblyLoc );
                        const string manifestName = "XPThemes.manifest";
                        manifestLoc = Path.Combine( installDir, manifestName );
                    }

                    if ( manifestLoc != null && installDir != null ) {
                        enableThemingActivationContext = new ACTCTX();
                        enableThemingActivationContext.cbSize = Marshal.SizeOf( typeof( ACTCTX ) );
                        enableThemingActivationContext.lpSource = manifestLoc;

                        // Set the lpAssemblyDirectory to the install
                        // directory to prevent Win32 Side by Side from
                        // looking for comctl32 in the application
                        // directory, which could cause a bogus dll to be
                        // placed there and open a security hole.
                        enableThemingActivationContext.lpAssemblyDirectory = installDir;
                        enableThemingActivationContext.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;

                        // Note this will fail gracefully if file specified
                        // by manifestLoc doesn't exist.
                        hActCtx = CreateActCtx( ref enableThemingActivationContext );
                        contextCreationSucceeded = (hActCtx != new IntPtr( -1 ));
                    }
                }

                // If we return false, we'll try again on the next call into
                // EnsureActivateContextCreated(), which is fine.
                return contextCreationSucceeded;
            }
        }

        // All the pinvoke goo...
        [DllImport( "Kernel32.dll" )]
        private extern static IntPtr CreateActCtx( ref ACTCTX actctx );
        [DllImport( "Kernel32.dll" )]
        private extern static bool ActivateActCtx( IntPtr hActCtx, out uint lpCookie );
        [DllImport( "Kernel32.dll" )]
        private extern static bool DeactivateActCtx( uint dwFlags, uint lpCookie );

        private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;

        private struct ACTCTX {
            public int cbSize;
            public uint dwFlags;
            public string lpSource;
            public ushort wProcessorArchitecture;
            public ushort wLangId;
            public string lpAssemblyDirectory;
            public string lpResourceName;
            public string lpApplicationName;
        }
    }
}

然后在第93行的 Core \ Interop \ TaskDialogs \ NativeTaskDialog.cs 中(上面的 HResult hresult = TaskDialogNativeMethods.TaskDialogIndirect )使该部分看起来像这样(最后你将有三个新行:

// Here is the way we use "vanilla" P/Invoke to call TaskDialogIndirect().
HResult hresult;
using ( new EnableThemingInScope( true ) ) {
    hresult = TaskDialogNativeMethods.TaskDialogIndirect(
        nativeDialogConfig,
        out selectedButtonId,
        out selectedRadioButtonId,
        out checkBoxChecked );
}

答案 2 :(得分:1)

我在调试模式下遇到与Visual Studio相同的问题。到目前为止,我还没有找到解决方法,它在发布模式下工作正常。

答案 3 :(得分:0)

此页面介绍如何向项目添加自定义清单,以告知Windows加载新的comctl32.dll(版本6.0):

你的清单是否对comctl32.dll有正确的依赖?你是否嵌入了创建的清单?