Frage

Ich verwende den folgenden Code ein Taskdialog aufrufen.

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

Allerdings bekomme ich die Ausnahme „Kann nicht einen Einstiegspunkt finden namens‚TaskDialogIndirect‘in DLL‚Comctl32‘.“

Ich habe diesen Code . Ich verwende Windows 7 x64 (RC).

Was mache ich falsch?

War es hilfreich?

Lösung

Nichts, außer dies ist ein Vista-Funktion

UPDATE: Diese probem hatte mit nebeneinander Baugruppen zu tun: diese Funktionen nur in Comctl32.dll Version 6 vorhanden sind, aber aus Kompatibilitätsgründen, Vista wird eine frühere Version laden, wenn Sie es anders sagen. Die Vorgehensweise der meisten Menschen (ich eingeschlossen) genommen haben, ist es, ein Manifest zu verwenden. Dies hat sich als schwierig sein und kann nicht die richtige Lösung sowieso, vor allem, wenn das, was Sie schreiben eine Bibliothek ist. Sie müssen nicht die gesamte Anwendung erzwingen wollen 6 gemeinsame Kontrollen zu verwenden,

Die richtige Lösung ist eine neue Aktivierung drücken Kontext, wenn eine der Vista-only-APIs aufrufen. Die Aktivierung Kontext die richtige Version von comctl32.dll verwenden, während der Rest der Anwendung allein zu lassen, und kein offensichtlicher erforderlich ist.

Glücklicherweise ist dies einfach vollständigen Code do.Some, die bereits vorhanden MS Knowledagebase . Der Code aus dem Artikel (KB 830033) funktioniert der Trick, wie ist.

Alternative Managed API: Eine vollständige Wrapper für Vista & Taskdialog TaskDialogIndirect finden Sie hier:

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

Für WPF verwenden Sie die folgende:

Laden Sie die 'VistaBridge Sample Library' von http://code.msdn.microsoft.com/VistaBridge einmal heruntergeladen haben, öffnen Sie das Projekt und dann bauen (wenn Sie durch den gesamten Code aussehen wollen, die Dateien in den \ Library oder \ Interop Ordner untersuchen). Sie können nun die DLL aus VistaBridge \ bin \ debug \ nehmen und einen Verweis auf sie in Ihrem Projekt hinzufügen, auch eine using-Anweisung für jede der verschiedenen VistaBridge Module hinzufügen. Zum Beispiel:

mit Microsoft.SDK.Samples.VistaBridge.Interop oder .library oder .Properties oder .Services -. Je nach Bedarf

Das VistaBridge Projekt umfasst API für viele anderen Vista-Features (wie zB den Taskdialog, Vista und Openfile Savefile Dialoge, und natürlich die Aero Glass Effekte) diese aus, um zu versuchen, das VistaBridge Projekt.

Andere Tipps

Die Verwendung von Task-Dialog erfordert Version 6 des Windows Common Controls DLL (ComCtl32.dll)! Aus Gründen der Kompatibilität von Anwendungen binden nicht an diese Version standardmäßig. Eine Möglichkeit, zu binden, zu der Version 6 ist eine Manifest-Datei neben ausführbaren zu platzieren (benannt YourAppName.exe.manifest), mit folgendem Inhalt:

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

Dieses Manifest kann auch als Win32-Ressource in Ihrem ausführbaren eingebettet werden (mit dem Namen RT_MANIFEST und ID auf 1 gesetzt), wenn Sie die zusätzliche eigenständige Datei haben, nicht wollen. Visual Studio kann diese Arbeit für Sie tun, wenn Sie Ihre Manifest-Datei in Ihrem Projekteigenschaften zuordnen.

Basierend auf almog.ori Antwort (die einige verwaiste Links bekam) machte ich eine kleine Änderung an dem Code verbunden, ich verwirrt mehrere Tage um:

MS Knowledagebase geholfen ( Archiv ), Voll Code mit Adoptionen von mir:

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

Ich habe es dann so:

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

in TaskDialogInterop.cs vorgesehen in WPF Task-Dialog Wrapper auf GitHub

Für weitere Informationen über mögliche SEHExceptions im Finalizer von EnableThemingInScope sieht diese Frage zum SO

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top