【问题标题】:EntryPointNotFoundException when using TaskDialog in C#在 C# 中使用 TaskDialog 时出现 EntryPointNotFoundException
【发布时间】:2009-10-23 09:34:22
【问题描述】:

我正在使用以下代码来调用 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);

但是,我收到异常“无法在 DLL 'ComCtl32' 中找到名为 'TaskDialogIndirect' 的入口点。”

我拿了this code。我使用的是 Windows 7 x64 (RC)。

我做错了什么?

【问题讨论】:

    标签: c# windows-7 pinvoke taskdialog


    【解决方案1】:

    除此之外没有其他功能

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

    正确的解决方案是在调用其中一个仅限 Vista 的 API 时推送 new activation 上下文。激活上下文将使用正确版本的 comctl32.dll,同时不理会应用程序的其余部分,并且不需要清单。

    幸运的是,这很容易做到。一些完整的代码已经存在MS Knowledgebase。文章 (KB 830033) 中的代码可以做到这一点。

    替代托管 API: Vista 的 TaskDialog 和 TaskDialogIndirect 的完整包装可以在这里找到:

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

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

    http://code.msdn.microsoft.com/VistaBridge 下载“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 项目。

    【讨论】:

    • VistaBridge 成为 Windows API 代码包。
    【解决方案2】:

    使用任务对话框需要版本 6 的 Windows 通用控件 DLL(ComCtl32.dll)!出于兼容性原因,默认情况下应用程序不会绑定到此版本。绑定到版本 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】:

      根据 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

      有关EnableThemingInScope 的终结器中可能的SEHExceptions 的更多信息,请参阅此Question on SO

      【讨论】:

      • 这个答案对于让它发挥作用至关重要。感谢您提供仅作为存档提供的代码。
      猜你喜欢
      • 2012-10-05
      • 1970-01-01
      • 2021-04-12
      • 2022-01-19
      • 1970-01-01
      • 2014-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多