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

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

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 ///  /// 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. ///  [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; } } } 

我最近在使用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 ///  /// 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. ///  [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 ); } 

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

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

  • 设置正确的清单版本

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