2009-09-12 22 views
6

Estoy usando el WindowsAPICodePack para TaskDialog. Cuando trato de mostrar el diálogo, dice que necesita cargar la versión 6 de comctl32.dll. Así que agregué la versión 6 a la aplicación. Manifesté y traté de ejecutarla. Todavía sin suerte. Fui a la carpeta Debug y ejecuté el programa sin Visual Studio y funciona bien. Supongo que Visual Studio no está usando el archivo de manifiesto ... Me preguntaba si había una manera de hacerlo.C#: comctl32.dll versión 6 en el depurador

Respuesta

9

Rob pol86, su código arroja SEHExceptions, porque las firmas para ActivateActCtx y DeactivateActCtx no son correctas. Debe usar UIntPtr en lugar de uint para lpCookie.

Por lo tanto, el código correcto para EnableThemingInScope.cs sería:

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; 
     } 
    } 
} 
+0

Saludos, esta es la respuesta correcta. No es necesario cambiar el manifiesto con esto. –

+0

+1 Para una respuesta correcta. Para referencia futura, tuve una implementación de cookie uint similar rota de este artículo de la base de conocimiento msdn: https://support.microsoft.com/en-us/kb/830033 solo por claridad: pude crear el alcance pero luego obtuve un SEH Excepción en DeactivateActCtx. una mayor depuración reveló que era el código de error 6, que es ERROR_INVALID_HANDLE ya que la cookie no se podía usar para desactivar el contexto correctamente debido a su tipo incorrecto. – Samuel

+0

¡Gracias! Estaba teniendo problemas con comctl32.dll al publicar ClickOnce, y esto lo resolvió – dariusc

0

Esta página describe cómo agregar un manifiesto a medida para su proyecto con el fin de indicar a Windows para cargar el nuevo comctl32.dll (versión 6.0):

¿Su tienen manifiesta la dependencia correcta en comctl32.dll? ¿Incrustaste el manifiesto creado?

1

Tengo el mismo problema con Visual Studio en el modo de depuración. Hasta ahora no he encontrado una solución, funciona bien en el modo de lanzamiento.

4

Recientemente me encontré con este problema al depurar código con el TaskDialogDemo en el CodePack. Así es como lo solucioné. El problema con el uso de esto es si abro dos o tres cuadros de diálogo arroja una SEHException, que no he descubierto cómo solucionarlo. Entonces el comprador se guarda.

Añadir 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; 
     } 
    } 
} 

Luego, en Core \ Interop \ TaskDialogs \ NativeTaskDialog.cs en la línea 93 (por encima de HResult hresult = TaskDialogNativeMethods.TaskDialogIndirect) haga que la sección se vea así (al final tendrá tres líneas nuevas):

// 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); 
} 
Cuestiones relacionadas