2010-07-10 3 views
7

Win32 활성화 메시지를 처리 ​​할 수 ​​있도록 일부 WPF 윈도우의 Win32 윈도우 핸들에 액세스해야합니다. PresentationSource.FromVisual 또는 WindowInteropHelper을 사용하여 Win32 창 핸들을 얻을 수 있지만 WPF 창이 아직 작성되지 않은 경우 문제점이 있음을 알고 있습니다.WPF 창의 네이티브 Win32 핸들 생성하기

PresentationSource.FromVisual을 사용하고 창을 만들지 않은 경우 반환 된 PresentationSource은 null입니다. WindowInteropHelper을 사용하고 창을 만들지 않았다면 Handle 속성은 IntPtr.Zero (null)입니다.

핸들에 액세스하려고하기 전에 창에 this.Show()this.Hide()을 호출 해 보았습니다. 그런 다음 핸들을 얻을 수 있지만 화면이 순간적으로 깜박입니다 (못생긴!).

누군가 WPF 창을 강제로 생성하는 방법을 알고 있습니까? Windows Forms에서는 Form.Handle 속성에 액세스하는 것만 큼 쉽습니다.

편집 : Chris Taylor의 답변에 변형이 있습니다. 여기에는, 경우에 다른 사람 도움이된다

static void InitializeWindow(Window window) 
{ 
    // Get the current values of the properties we are going to change 
    double oldWidth = window.Width; 
    double oldHeight = window.Height; 
    WindowStyle oldWindowStyle = window.WindowStyle; 
    bool oldShowInTaskbar = window.ShowInTaskbar; 
    bool oldShowActivated = window.ShowActivated; 

    // Change the properties to make the window invisible 
    window.Width = 0; 
    window.Height = 0; 
    window.WindowStyle = WindowStyle.None; 
    window.ShowInTaskbar = false; 
    window.ShowActivated = false; 

    // Make WPF create the window's handle 
    window.Show(); 
    window.Hide(); 

    // Restore the old values 
    window.Width = oldWidth; 
    window.Height = oldHeight; 
    window.WindowStyle = oldWindowStyle; 
    window.ShowInTaskbar = oldShowInTaskbar; 
    window.ShowActivated = oldShowActivated; 
} 

// Use it like this: 
InitializeWindow(myWpfWindow); 
+0

이 질문을 본 적이 있으신가요? http://stackoverflow.com/questions/1556182/finding-the-handle-to-a-wpf-window- 창이 이미 존재하는지 언급하지 않으므로 도움이되지 않을 수 있습니다. 아닙니다. – ChrisF

+0

@ChrisF : 감사합니다! 예, 나는 그것을 보았습니다. 불행히도 아직 창을 만들지 못하는 문제가 있습니다. –

+0

귀하의 사례가 다른 경우 중복으로 선택되지 않도록 귀하의 회신을 받기 위해 언급하겠다고 생각했습니다. – ChrisF

답변

3

하나의 옵션을 최소화로 윈도우 상태를 설정하고 창을보기 전에 작업 표시 줄에 표시되지 않습니다. 이런 식으로 해보십시오.

IntPtr hWnd; 
    WindowInteropHelper helper = new WindowInteropHelper(wnd); 

    WindowState prevState = wnd.WindowState; 
    bool prevShowInTaskBar = wnd.ShowInTaskbar; 

    wnd.ShowInTaskbar = false; 
    wnd.WindowState = WindowState.Minimized; 
    wnd.Show(); 
    hWnd = helper.Handle; 
    wnd.Hide(); 

    wnd.ShowInTaskbar = prevShowInTaskBar; 
    wnd.WindowState = prevState; 
+0

고마워요! 나는 이것의 변종으로 끝났다. (질문에 대한 나의 편집을 보아라.) –

+2

[@ DanielAlbuschat 's answer] (http://stackoverflow.com/a/4826741/24874)는 더 간단하고 깜박임을 방지합니다. –

+0

예, 아래 답변은 훨씬 깔끔합니다. –

17

WindowInteropHelper.EnsureHandle을 사용하면 정확하게 필요한 작업을 수행 할 수 있습니다.

+0

+1 멋진 찾기! 나는 그것을 시험해야 할 것이다. –

+0

나는 똑같은 문제를 겪었고, 이것이 최고의 대답이다! – laishiekai

+0

다시 말하지만, 이것은 받아 들여진 것보다 훨씬 더 나은 대답입니다! 여러분, 대신 이것을 사용하십시오! –

2

WindowInteropHelper의 핸들이 NULL 인 경우 솔루션을 찾고있었습니다. 잘하면이 게시물은 그것을 해결하는 방법에 대한 몇 가지 추가 정보를 제공합니다.

하나의 해결책은 사용하는 것입니다

var window = new Window(); 
var handle = new WindowInteropHelper(window).EnsureHandle() 

이것은 내가 그래서 다른 솔루션이 필요 .NET 프레임 워크 3.5을 사용하고있는 순간 .NET 프레임 워크 4

에서만 작동합니다.

#region 

using System; 
using System.Reflection; 
using System.Windows; 
using System.Windows.Interop; 

#endregion 

namespace System.Windows.Interop 
{ 
    /// <summary> 
    /// Provides NetFX 4.0 EnsureHandle method for 
    /// NetFX 3.5 WindowInteropHelper class. 
    /// </summary> 
    public static class WindowInteropHelperExtension 
    { 
     /// <summary> 
     /// Creates the HWND of the window if the HWND has not been created yet. 
     /// </summary> 
     /// <param name = "helper">An instance of WindowInteropHelper class.</param> 
     /// <returns>An IntPtr that represents the HWND.</returns> 
     /// <remarks> 
     /// Use the EnsureHandle method when you want to separate 
     /// window handle (HWND) creation from the 
     /// actual showing of the managed Window. 
     /// </remarks> 
     public static IntPtr EnsureHandle(this WindowInteropHelper helper) 
     { 
      if (helper == null) 
       throw new ArgumentNullException("helper"); 

      if (helper.Handle == IntPtr.Zero) 
      { 
       var window = (Window) typeof (WindowInteropHelper).InvokeMember(
        "_window", 
        BindingFlags.GetField | 
        BindingFlags.Instance | 
        BindingFlags.NonPublic, 
        null, helper, null); 

       typeof (Window).InvokeMember(
        "SafeCreateWindow", 
        BindingFlags.InvokeMethod | 
        BindingFlags.Instance | 
        BindingFlags.NonPublic, 
        null, window, null); 
      } 

      return helper.Handle; 
     } 
    } 
} 

WindowInteropHelper.EnsureHandle() 윈도우가 이미 생성되어 기대하지 않습니다 그리고 나는 WindowInteropHelper 확장 방법 포럼 스레드를 발견했다.

참조 : 알렉산더 Yudakov - http://social.msdn.microsoft.com/Forums/en-MY/wpf/thread/5f89ac58-d2ef-4ac0-aefb-b2826dbef48a

0

나는이 같은 문제에 붙어하고 (그것이 나에게 청소기 것 때문에) J Pollack's answer 갔다하지만, .NET 런타임에서 모두 실행할 무언가를 필요로했다 2.0 및 4.0.

하지만 난 더 이상 .NET 런타임 4.0에 존재하지 않는 추한 MissingMethodException SafeCreateWindow 때문으로 결국 것을했을 때. 나는 MissingMethodException이를 잡기로 결정 모두 런타임에 코드가 작동하고 대신이 같은 .NET 4.0 런타임에서 해당 호출하려면 :이 날 .NET 3.5 코드를 컴파일 만에 그것을 실행할 수

public static IntPtr EnsureHandle(this WindowInteropHelper helper) 
    { 
     if (helper == null) 
      throw new ArgumentNullException("helper"); 

     if (helper.Handle == IntPtr.Zero) 
     { 
      var window = (Window)typeof(WindowInteropHelper).InvokeMember(
       "_window", 
       BindingFlags.GetField | 
       BindingFlags.Instance | 
       BindingFlags.NonPublic, 
       null, helper, null); 

      try 
      { 
       // SafeCreateWindow only exists in the .NET 2.0 runtime. If we try to 
       // invoke this method on the .NET 4.0 runtime it will result in a 
       // MissingMethodException, see below. 
       typeof(Window).InvokeMember(
        "SafeCreateWindow", 
        BindingFlags.InvokeMethod | 
        BindingFlags.Instance | 
        BindingFlags.NonPublic, 
        null, window, null); 
      } 
      catch (MissingMethodException) 
      { 
       // If we ended up here it means we are running on the .NET 4.0 runtime, 
       // where the method we need to call for the handle was renamed/replaced 
       // with CreateSourceWindow. 
       typeof(Window).InvokeMember(
        "CreateSourceWindow", 
        BindingFlags.InvokeMethod | 
        BindingFlags.Instance | 
        BindingFlags.NonPublic, 
        null, window, new object[] { false }); 
      } 
     } 

     return helper.Handle; 
    } 

을 .NET 런타임 4.0보다 높은 런타임 버전 만 설치된 시스템에서는 (즉, Windows 8 이상).

관련 문제