EntryPointNotFoundException при использовании TaskDialog в C #

Я использую следующий код для вызова 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);

Однако я получаю исключение «Невозможно найти точку входа с именем« TaskDialogIndirect »в DLL« ComCtl32 »».

Я взял этот код. Я использую Windows 7 x64 (RC).

Что я делаю неправильно?


person Vivelin    schedule 23.10.2009    source источник


Ответы (3)


Ничего, кроме этого, особенность перспективы

ОБНОВЛЕНИЕ: эта проблема была связана с параллельными сборками: эти функции присутствуют только в comctl32.dll версии 6, но по соображениям совместимости Vista загрузит более раннюю версию, если вы не укажете иное. Большинство людей (включая меня) используют манифест. Это оказалось непростой задачей и в любом случае может быть неправильным решением, особенно если то, что вы пишете, является библиотекой: вам не обязательно заставлять все приложение использовать общие элементы управления 6.

Правильное решение - запустить новую активацию контекст при вызове одного из API только для Vista. Контекст активации будет использовать правильную версию comctl32.dll, оставив остальную часть приложения в покое, и манифест не требуется.

К счастью, это легко сделать. Некоторый полный код уже существует в базе знаний MS. Код из статьи (KB 830033) как есть.

Альтернативный управляемый API: полную оболочку для Vista TaskDialog и TaskDialogIndirect можно найти здесь:

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

Для WPF используйте следующее:

Загрузите "Библиотеку образцов VistaBridge" со страницы http://code.msdn.microsoft.com/VistaBridge после загрузки откройте проект и затем соберите его (если вы хотите просмотреть весь код, проверьте файлы в папках \ Library или \ Interop). Теперь вы можете взять DLL из VistaBridge \ bin \ debug \ и добавить ссылку на нее в свой проект, а также вы должны добавить оператор using для каждого из различных модулей VistaBridge. Например:

используя Microsoft.SDK.Samples.VistaBridge.Interop или .Library, или .Properties, или .Services - в зависимости от ваших потребностей.

Проект VistaBridge включает API-интерфейсы для многих других функций Vista (таких как диалоги TaskDialog, Vista OpenFile и SaveFile и, конечно же, эффекты Aero Glass), чтобы опробовать их, запустить проект VistaBridge.

person almog.ori    schedule 23.10.2009
comment
VistaBridge стала пакетом кода Windows API. - person Kate Gregory; 14.06.2010

Для использования диалогового окна задач требуется версия 6 DLL Windows Common Controls (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 и идентификатором, равным 1), если вы не хотите иметь дополнительный автономный файл. Visual Studio может сделать эту работу за вас, если вы свяжете файл манифеста в свойствах проекта.

person Mani Sharma    schedule 15.07.2013

Основываясь на ответе almog.ori (в котором есть несколько осиротевших ссылок), я внес небольшое изменение в связанный код, я ломал голову несколько дней:

Помогла База знаний MS (Архив), Полный код с изменениями, сделанными мной:

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 на GitHub

Для получения дополнительной информации о возможных SEHException в финализаторе EnableThemingInScope см. Этот Вопрос по SO

person Creepin    schedule 21.02.2019
comment
Этот ответ важен, чтобы заставить его работать. Благодарим вас за то, что вы предложили код, который больше доступен только в виде архива. - person A Person; 01.03.2021