2009-09-12 22 views
6

Sto utilizzando il WindowsAPICodePack per TaskDialog. Quando provo a mostrare la finestra di dialogo, dice che è necessario caricare la versione 6 di comctl32.dll. Così ho aggiunto la versione 6 a app.manifest e ho provato a eseguirlo. Ancora senza fortuna. Sono andato alla cartella Debug e ho eseguito il programma senza Visual Studio e funziona perfettamente. Immagino che Visual Studio non stia utilizzando il file manifest ... Mi chiedevo se c'era un modo per farlo.C#: comctl32.dll versione 6 nel debugger

risposta

9

Rob pol86, il tuo codice lancia SEHExceptions, perché le firme per ActivateActCtx e DeactivateActCtx non sono corrette. Devi usare UIntPtr invece di uint per lpCookie.

Pertanto, il codice corretto per EnableThemingInScope.cs sarebbe:

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

Cheers, questa è la risposta corretta. Non c'è bisogno di cambiare manifest con questo. –

+0

+1 per la risposta corretta. Per riferimento futuro ho avuto un'implementazione di cookie uint simile da questo articolo della knowledge base di msdn: https://support.microsoft.com/en-us/kb/830033 solo per chiarezza: ho potuto creare l'ambito ma poi ho ottenuto un SEH Eccezione su DeactivateActCtx. ulteriori debug hanno rivelato che si trattava del codice di errore 6, che è ERROR_INVALID_HANDLE in quanto il cookie non poteva essere utilizzato per disattivare correttamente il contesto a causa del suo tipo errato. – Samuel

+0

Grazie! Avevo problemi con comctl32.dll durante la pubblicazione di ClickOnce, e questo lo risolse – dariusc

0

Questa pagina descrive come aggiungere un manifesto personalizzato al progetto, al fine di dire a Windows per caricare il nuovo comctl32.dll (versione 6.0):

Il vostro hanno manifestato la giusta dipendenza su comctl32.dll? Hai incorporato il manifest creato?

1

Ho lo stesso problema con Visual Studio in modalità Debug. Finora non ho trovato una soluzione alternativa, funziona bene in modalità di rilascio.

4

Recentemente mi sono imbattuto in questo problema durante il debug del codice con TaskDialogDemo nel CodePack. Questo è il modo in cui l'ho risolto. Il problema con l'utilizzo di questo è se apro due o tre finestre di dialogo lancia una SEHException, che non ho capito come risolvere. Quindi il compratore si guarda.

Aggiungere 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; 
     } 
    } 
} 

Poi nel Core \ Interop \ TaskDialogs \ NativeTaskDialog.cs sulla linea 93 (sopra HResult hresult = TaskDialogNativeMethods.TaskDialogIndirect) rendere il look sezione come questo (alla fine si avrà tre nuove linee):

// 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); 
} 
Problemi correlati