代码之家  ›  专栏  ›  技术社区  ›  Vivelin

在C中使用taskdialog时EntryPointNotFoundException#

  •  7
  • Vivelin  · 技术社区  · 16 年前

    我正在使用以下代码调用任务对话框。

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

    但是,我得到一个异常:“在dll'comctl32'中找不到名为'taskdialogindirect'的入口点。”

    我采取 this code . 我使用的是Windows7x64(rc)。

    我做错什么了?

    3 回复  |  直到 7 年前
        1
  •  8
  •   almog.ori    16 年前

    除了这是一个Vista功能外,什么都没有

    更新: 这个问题与并行程序集有关:这些函数仅存在于comctl32.dll版本6中,但是,出于兼容性的原因,Vista将加载早期版本,除非您另有说明。大多数人(包括我)一直采用的方法是使用清单。事实证明,这是一个棘手的问题,而且可能不是正确的解决方案,尤其是如果您正在编写的是一个库:您不必强制整个应用程序使用公共控件6。

    正确的解决方案是 new activation 调用一个仅限Vista的API时的上下文。激活上下文将使用正确版本的comctl32.dll,而只保留应用程序的其余部分,不需要清单。

    幸运的是,这很容易做到。一些已经存在的完整代码 MS Knowledgebase . 文章中的代码(Kb830033)按原样完成了这个技巧。

    替代托管API: 可以在此处找到Vista任务对话框和任务对话框间接的完整包装:

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

    对于WPF,请使用以下内容:

    从下载“vistabridge示例库” http://code.msdn.microsoft.com/VistaBridge 下载后,打开项目,然后构建它(如果要查看所有代码,请检查\library或\interop文件夹中的文件)。现在,您可以从vistabridge\bin\debug\中获取dll,并在项目中添加对它的引用,还必须为每个不同的vistabridge模块添加using语句。例如:

    根据需要使用Microsoft.sdk.samples.vistabridge.interop或.library或.properties或.services。

    vistabridge项目包括许多其他vista功能的API(如taskdialog、vista openfile和savefile对话框,当然还有aero glass效果),要尝试这些功能,请运行vistabridge项目。

        2
  •  3
  •   Mani Sharma    13 年前

    使用任务对话框需要Windows Common Controls dll(comctl32.dll)的版本6!出于兼容性原因,应用程序默认不绑定到此版本。绑定到版本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>
    

    如果您不想拥有额外的独立文件,也可以将此清单作为Win32资源嵌入到可执行文件中(名称rt_manifest和id设置为1)。如果将清单文件关联到项目的属性中,Visual Studio可以为您完成这项工作。

        3
  •  0
  •   Creepin    7 年前

    基于almog.ori的答案(有一些孤立的链接),我对链接的代码做了一个小的更改,我困惑了几天:

    MS Knowledgebase 帮助( 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;
      }
     }
    }
    

    然后我用这种方式:

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

    在里面 TaskDialogInterop.cs 提供于 WPF Task Dialog Wrapper on GitHub

    有关可能的更多信息 SEHException 在的终结器中 EnableThemingInScope 看到这个 Question on SO