简体   繁体   English

在C#中使用TaskDialog时的EntryPointNotFoundException

[英]EntryPointNotFoundException when using TaskDialog in C#

I'm using the following code to call a TaskDialog. 我正在使用以下代码来调用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);

However, I get the exception "Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'." 但是,我得到异常“无法在DLL'ComCtl32'中找到名为'TaskDialogIndirect'的入口点。”

I took this code . 我拿了这个代码 I am using Windows 7 x64 (RC). 我使用的是Windows 7 x64(RC)。

What am I doing wrong? 我究竟做错了什么?

Nothing except this is a vista feature 除此之外没有任何东西是vista功能

UPDATE: This probem had to do with side by side assemblies: these functions are present only in comctl32.dll version 6, but, for compatibility reasons, Vista will load an earlier version unless you tell it otherwise. 更新:此探针与并排程序集有关:这些函数仅存在于comctl32.dll版本6中,但出于兼容性原因,Vista将加载早期版本,除非您另有说明。 The approach most people (including me) have been taking is to use a manifest. 大多数人(包括我)采取的方法是使用清单。 This has proven to be tricky, and may not be the right solution anyway, especially if what you're writing is a library: you don't necessarily want to force the entire application to use common controls 6. 这已被证明是棘手的,并且可能不是正确的解决方案,特别是如果您正在编写的是库:您不一定要强制整个应用程序使用通用控件6。

The right solution is to push a new activation context when calling one of the Vista-only APIs. 正确的解决方案是在调用其中一个仅限Vista的API时推送新的激活上下文。 The activation context will use the correct version of comctl32.dll while leaving the rest of the application alone, and no manifest is required. 激活上下文将使用正确版本的comctl32.dll,而单独保留应用程序的其余部分,并且不需要清单。

Fortunately, this is easy to do.Some complete code that already exists MS Knowledgebase . 幸运的是,这很容易做到。一些已经存在的完整代码MS知识库 The code from the article (KB 830033) does the trick as is. 文章中的代码(KB 830033)就是这样做的。

Alternative Managed API: A full wrapper for Vista's TaskDialog & TaskDialogIndirect can be found here: 替代托管API:可以在此处找到Vista的TaskDialog和TaskDialogIndirect的完整包装:

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

For WPF use the following: 对于WPF,请使用以下内容:

Download the 'VistaBridge Sample Library' from http://code.msdn.microsoft.com/VistaBridge once downloaded, open the project and then build it (if you want to look through all the code, examine the files in the \\Library or \\Interop folders). 下载后从http://code.msdn.microsoft.com/VistaBridge下载'VistaBridge示例库',打开项目然后构建它(如果要查看所有代码,请检查\\ Library中的文件或\\ Interop文件夹)。 You can now take the DLL from VistaBridge\\bin\\debug\\ and add a reference to it in your project, as well you must add a using statement for each of the different VistaBridge modules. 您现在可以从VistaBridge \\ bin \\ debug \\中获取DLL,并在项目中添加对它的引用,并且必须为每个不同的VistaBridge模块添加using语句。 For Example: 例如:

using Microsoft.SDK.Samples.VistaBridge.Interop or .Library or .Properties or .Services - Depending on your needs. 使用Microsoft.SDK.Samples.VistaBridge.Interop或.Library或.Properties或.Services - 根据您的需要。

The VistaBridge project includes API's for many other Vista Features (such as the TaskDialog, Vista OpenFile and SaveFile Dialogs, and of course the Aero Glass Effects) to try these out, run the VistaBridge Project. VistaBridge项目包括用于许多其他Vista功能的API(例如TaskDialog,Vista OpenFile和SaveFile对话,当然还有Aero Glass Effects)来试用这些功能,运行VistaBridge项目。

The use of Task Dialog requires version 6 of the Windows Common Controls DLL(ComCtl32.dll)! 使用Task Dialog需要Windows Common Controls DLL(ComCtl32.dll)的第6版! For compatibility reasons, applications don't bind to this version by default. 出于兼容性原因,默认情况下应用程序不绑定到此版本。 One way to bind to version 6 is to place a manifest file alongside your executable (named YourAppName.exe.manifest), with the following content: 绑定到版本6的一种方法是将清单文件放在可执行文件旁边(名为YourAppName.exe.manifest),其中包含以下内容:

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

This manifest can also be embedded as a Win32 resource inside your executable (with the name RT_MANIFEST and ID set to 1), if you don't want to have the extra standalone file. 如果您不想拥有额外的独立文件,此清单也可以作为Win32资源嵌入您的可执行文件中(名称为RT_MANIFEST,ID设置为1)。 Visual Studio can do this work for you, if you associate your manifest file in your project's properties. 如果将清单文件关联到项目的属性中,Visual Studio可以为您完成此工作。

Based on almog.ori's answer (which got some orphaned links) I made a small change to the linked code, I puzzled around several days: 基于almog.ori的回答(它有一些孤立的链接)我对链接代码进行了一些小改动,我困惑了好几天:

MS Knowledgebase helped ( Archiv ), Full Code with adoptions made by me: MS知识库帮助( Archiv ),完整代码由我收养:

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

I then used it that way: 然后我用它那样:

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 provided in WPF Task Dialog Wrapper on GitHub GitHub上的WPF Task Dialog Wrapper中提供的TaskDialogInterop.cs

For more info on possible SEHException s in the Finalizer of EnableThemingInScope see this Question on SO 有关EnableThemingInScope的Finalizer中可能的SEHException的更多信息,请参阅SO上的这个问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM