C#:调试器中的 comctl32.dll 版本 6
Posted
技术标签:
【中文标题】C#:调试器中的 comctl32.dll 版本 6【英文标题】:C#: comctl32.dll version 6 in debugger 【发布时间】:2009-09-12 14:33:14 【问题描述】:我将WindowsAPICodePack 用于TaskDialog。当我尝试显示对话框时,它说它需要加载 comctl32.dll 的版本 6。所以我将版本 6 添加到 app.manifest 并尝试运行它。仍然没有运气。我去了 Debug 文件夹并在没有 Visual Studio 的情况下运行程序,它工作正常。我猜 Visual Studio 没有使用清单文件...我想知道是否有办法让它这样做。
【问题讨论】:
我们能否将确切的错误消息添加到问题中,以便 Google 在这里引导它?这对我来说是正确的答案,但我只在其他线程中发现模糊的提及,最终不得不搜索“EnableThemingInScope”才能到达这里。以下是 Google 爬虫的错误消息:“TaskDialog 功能需要加载 comctl32.dll 的第 6 版,但内存中当前加载了不同的版本”,内部异常“无法在 DLL 'Comctl32.dll 中找到名为 'TaskDialogIndirect' 的入口点” '。” 【参考方案1】: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 正确答案。为了将来参考,我从这篇 msdn 知识库文章中获得了类似的损坏的 uint cookie 实现:support.microsoft.com/en-us/kb/830033 只是为了清楚起见:我可以创建范围,但随后我在 DeactivateActCtx 上得到了一个 SEH 异常。进一步调试显示它是错误代码 6,即 ERROR_INVALID_HANDLE,因为 cookie 无法用于正确停用上下文,因为它的类型错误。 谢谢!我在发布 ClickOnce 时遇到了 comctl32.dll 问题,这解决了它【参考方案2】:我最近在使用 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 );
【讨论】:
【参考方案3】:本页介绍了如何将自定义清单添加到您的项目中,以告知 Windows 加载新的 comctl32.dll(6.0 版):
Setting the correct manifest version您的清单是否正确依赖 comctl32.dll?您是否嵌入了创建的清单?
【讨论】:
【参考方案4】:我在调试模式下使用 Visual Studio 时遇到同样的问题。到目前为止我还没有找到解决方法,它在发布模式下可以正常工作。
【讨论】:
以上是关于C#:调试器中的 comctl32.dll 版本 6的主要内容,如果未能解决你的问题,请参考以下文章
覆盖 UWP 中的 WinSxS 机制。专门针对 ComCtl32.dll