Question

J'utilise le code suivant pour appeler un TaskDialog.

    [DllImport("ComCtl32", CharSet = CharSet.Unicode, PreserveSig = false)]
    internal static extern void TaskDialogIndirect(
        [In] ref TASKDIALOGCONFIG pTaskConfig,
        [Out] out int pnButton,
        [Out] out int pnRadioButton,
        [Out] out bool pfVerificationFlagChecked);

Toutefois, l'exception "" Impossible de trouver un point d'entrée nommé "TaskDialogIndirect" dans la DLL "ComCtl32". "

J'ai pris ce code . J'utilise Windows 7 x64 (RC).

Qu'est-ce que je fais de travers?

Était-ce utile?

La solution

Rien à part ceci est une fonctionnalité de vista

UPDATE: Ce problème concernait les assemblages côte à côte: ces fonctions ne sont présentes que dans la version 6 de comctl32.dll, mais, pour des raisons de compatibilité, Vista chargera une version antérieure, sauf indication contraire de votre part. L’approche que la plupart des gens (y compris moi-même) avons adoptée consiste à utiliser un manifeste. Cela s’est avéré délicat et n’est peut-être pas la bonne solution, surtout si ce que vous écrivez est une bibliothèque: vous ne voulez pas forcer l’application entière à utiliser des contrôles communs 6.

La bonne solution consiste à pousser une nouvelle activation context lors de l'appel de l'une des API réservées à Vista. Le contexte d'activation utilisera la version correcte de comctl32.dll tout en laissant le reste de l'application seule, et aucun manifeste n'est requis.

Heureusement, cela est facile à faire.Certains codes complets déjà existants Base de connaissances MS . Le code de l'article (KB 830033) fait l'affaire en l'état.

Autre API gérée: Un wrapper complet pour TaskDialog & amp; de Vista TaskDialogIndirect peut être trouvé ici:

http://code.msdn.microsoft.com/WindowsAPICodePack

Pour WPF, utilisez les éléments suivants:

Téléchargez la bibliothèque d'échantillons VistaBridge à partir de http://code.msdn.microsoft.com/VistaBridge une fois téléchargé, ouvrez le projet, puis construisez-le (si vous souhaitez parcourir tout le code, examinez les fichiers des dossiers \ Library ou \ Interop). Vous pouvez maintenant extraire la DLL de VistaBridge \ bin \ debug \ et y ajouter une référence dans votre projet. Vous devez également ajouter une instruction using pour chacun des différents modules VistaBridge. Par exemple:

Utilisation de Microsoft.SDK.Samples.VistaBridge.Interop ou .Library ou .Properties ou .Services - En fonction de vos besoins.

Le projet VistaBridge inclut des API pour de nombreuses autres fonctionnalités de Vista (telles que les boîtes de dialogue TaskDialog, Vista OpenFile et SaveFile, et bien sûr les effets Aero Glass), pour les essayer, exécutez le projet VistaBridge.

Autres conseils

L'utilisation de la boîte de dialogue de tâches nécessite la version 6 de la DLL de contrôles communs Windows (ComCtl32.dll)! Pour des raisons de compatibilité, les applications ne se lient pas à cette version par défaut. Une façon de se connecter à la version 6 consiste à placer un fichier manifeste à côté de votre exécutable (nommé YourAppName.exe.manifest), avec le contenu suivant:

 <dependency>
    <dependentAssembly>
      <assemblyIdentity
          type="win32"
          name="Microsoft.Windows.Common-Controls"
          version="6.0.0.0"
          processorArchitecture="*"
          publicKeyToken="6595b64144ccf1df"
          language="*"
        />
    </dependentAssembly>
  </dependency>

Ce manifeste peut également être incorporé en tant que ressource Win32 dans votre exécutable (avec les noms RT_MANIFEST et ID définis sur 1), si vous ne souhaitez pas disposer du fichier autonome supplémentaire. Visual Studio peut effectuer ce travail pour vous si vous associez votre fichier manifeste aux propriétés de votre projet.

Sur la base de la réponse d'almog.ori (qui contient des liens orphelins), j'ai légèrement modifié le code lié. Je suis resté perplexe pendant plusieurs jours:

Base de connaissances MS aidé ( Archiv ), code complet avec les adoptions que j'ai effectuées:

using System.Runtime.InteropServices;
using System;
using System.Security;
using System.Security.Permissions;
using System.Collections;
using System.IO;
using System.Text;

namespace MyOfficeNetAddin
{
    /// <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 IntPtr cookie; // changed cookie from uint to IntPtr
   private static ACTCTX enableThemingActivationContext;
   private static IntPtr hActCtx;
   private static bool contextCreationSucceeded = false;

   public EnableThemingInScope(bool enable)
   {
     if (enable)
     {
       if (EnsureActivateContextCreated())
       {
         if (!ActivateActCtx(hActCtx, out cookie))
         {
           // Be sure cookie always zero if activation failed
           cookie = IntPtr.Zero;
         }
       }
     }
  }

  // Finalizer removed, that could cause Exceptions
  // ~EnableThemingInScope()
  // {
  //    Dispose(false);
  // }

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

  private void Dispose(bool disposing)
  {
     if (cookie != IntPtr.Zero)
     {
        if (DeactivateActCtx(0, cookie))
        {
           // deactivation succeeded...
           cookie = IntPtr.Zero;
        }
     }
  }

  private 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);

  // changed from uint to IntPtr according to 
  // https://www.pinvoke.net/default.aspx/kernel32.ActiveActCtx
  [DllImport("Kernel32.dll", SetLastError = true)]
  [return: MarshalAs(UnmanagedType.Bool)]
  private static extern bool ActivateActCtx(IntPtr hActCtx, out IntPtr lpCookie);

  // changed from uint to IntPtr according to 
  // https://www.pinvoke.net/default.aspx/kernel32.DeactivateActCtx
  [DllImport("Kernel32.dll", SetLastError = true)]
  [return: MarshalAs(UnmanagedType.Bool)]
  private static extern bool DeactivateActCtx(int dwFlags, IntPtr 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;
  }
 }
}

Je l'ai ensuite utilisé de cette façon:

using (new EnableThemingInScope(true))
{
    // The call all this mucking about is here for.
    VistaUnsafeNativeMethods.TaskDialogIndirect(ref config, out result, out radioButtonResult, out verificationFlagChecked);
 }

dans TaskDialogInterop.cs fourni dans Wrapper de dialogue de tâches WPF sur GitHub

Pour plus d'informations sur les SEHException possibles dans le Finalizer de EnableThemingInScope , consultez cette Question sur le SO

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top