문제

다음 코드를 사용하여 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'라는 진입 점을 찾을 수없는 예외를 얻습니다.

나는 가져 갔다 이 코드. Windows 7 X64 (RC)를 사용하고 있습니다.

내가 뭘 잘못하고 있죠?

도움이 되었습니까?

해결책

이것을 제외하고는 Vista 기능이 아닙니다

업데이트 :이 프로브는 나란히 어셈블리와 관련이 있어야했습니다. 이러한 기능은 Comctl32.dll 버전 6에만 존재하지만 호환성의 이유로 Vista는 달리 말하지 않으면 이전 버전을로드합니다. 대부분의 사람들 (나를 포함하여)이 취한 접근법은 매니페스트를 사용하는 것입니다. 이것은 까다로운 것으로 판명되었으며, 특히 당신이 쓰는 것이 도서관 인 경우 어쨌든 올바른 해결책이 아닐 수도 있습니다. 전체 응용 프로그램을 공통 컨트롤을 사용하도록 강요하고 싶지는 않습니다.

올바른 해결책은 a 새로운 활성화 Vista 전용 API 중 하나를 호출 할 때 컨텍스트. 활성화 컨텍스트는 응용 프로그램의 나머지 부분을 단독으로 남겨 두는 동안 올바른 버전의 comctl32.dll을 사용하며 매니페스트가 필요하지 않습니다.

다행히도 이것은 쉽게 수행 할 수 있습니다. 이미 존재하는 완전한 코드 MS Knowledgebase. 기사 (KB 830033)의 코드는 그대로 트릭을 수행합니다.

대체 관리 API : Vista의 TaskDialog 및 TaskDialoGindirect를위한 전체 포장지가 여기에서 찾을 수 있습니다.

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

WPF의 경우 다음을 사용하십시오.

'Vistabridge 샘플 라이브러리'를 다운로드하십시오 http://code.msdn.microsoft.com/vistabridge 다운로드 한 후 프로젝트를 열고 빌드 한 다음 빌드하십시오 (모든 코드를 살펴 보려면 library 또는 interop 폴더의 파일을 검사하십시오). 이제 Vistabridge bin debug 에서 DLL을 가져 와서 프로젝트에 참조를 추가 할 수 있습니다. 또한 각기 다른 Vistabridge 모듈에 대한 명령문을 추가해야합니다. 예를 들어:

필요에 따라 Microsoft.sdk.samples.vistabridge.interop 또는 .library 또는 .properties 또는 .services 사용.

Vistabridge 프로젝트에는 다른 많은 Vista 기능 (예 : TaskDialog, Vista OpenFile 및 SaveFile 대화 상자 및 Aero Glass Effects)에 대한 API가 포함되어있어 Vistabridge 프로젝트를 실행합니다.

다른 팁

작업 대화 상자를 사용하려면 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로 설정)로 포함될 수 있습니다. Visual Studio는 프로젝트 속성에 매니페스트 파일을 연결하면이 작업을 수행 할 수 있습니다.

Almog.ori의 답변 (고아 링크를 얻은)을 기반으로 링크 된 코드를 약간 변경했습니다. 며칠 동안 당황했습니다.

MS Knowledgebase 도움 (도움)아카이브), 저의 채택이있는 전체 코드 :

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 제공됩니다 github의 WPF 작업 대화 상자 래퍼

가능에 대한 자세한 정보 SEHException최종화기에서 EnableThemingInScope 이것 좀 봐 그렇게 질문

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top