다음을 통해 공유


자습서: Win32 응용 프로그램에서 시각적 개체 호스팅

Windows Presentation Foundation (WPF)에서는 응용 프로그램을 만들기 위한 다양한 환경을 제공합니다. 그러나 Win32 코드를 작성하는 데 많은 시간과 노력을 기울인 경우 이 코드를 다시 작성하는 대신 응용 프로그램에 WPF 기능을 추가하는 것이 더 효율적일 수 있습니다. 응용 프로그램에서 현재 동시에 사용되는 Win32 및 WPF 그래픽 하위 시스템을 모두 지원할 수 있도록 WPF에서는 Win32 창에 개체를 호스팅하는 메커니즘을 제공합니다.

이 자습서에서는 Win32 창에서 WPF 시각적 개체를 호스팅하는 샘플 응용 프로그램인 Hit Test with Win32 Interoperation 샘플을 작성하는 방법을 설명합니다.

이 항목에는 다음 단원이 포함되어 있습니다.

  • 요구 사항
  • 호스트 Win32 창 만들기
  • 호스트 Win32 창에 시각적 개체 추가
  • Win32 메시지 필터 구현
  • Win32 메시지 처리
  • 관련 항목

요구 사항

이 자습서에서는 사용자가 WPF 및 Win32 프로그래밍의 기본 사항에 대해 잘 알고 있다고 가정합니다. WPF 프로그래밍에 대한 소개는 연습: WPF 시작을 참조하십시오. Win32 프로그래밍에 대한 소개는 관련된 수많은 서적이 있지만, 특히 Charles Petzold의 Programming Windows가 도움이 될 것입니다.

참고참고

이 자습서에는 관련 샘플에 있는 많은 코드 예제가 포함되어 있지만편의상 전체 샘플 코드는 제공하지 않습니다.전체 샘플 코드를 보려면 Hit Test with Win32 Interoperation 샘플을 참조하십시오.

호스트 Win32 창 만들기

Win32 창에서 WPF 개체를 호스팅하는 데 핵심적인 역할을 하는 요소는 HwndSource 클래스입니다. 이 클래스를 사용하면 WPF 개체를 Win32 창에 래핑하여 user interface (UI)에 자식 창으로 통합할 수 있습니다.

다음 예제에서는 시각적 개체의 Win32 컨테이너 창으로 HwndSource 개체를 만드는 코드를 보여 줍니다. Win32 창의 창 스타일, 위치 및 다른 매개 변수를 설정하려면 HwndSourceParameters 개체를 사용합니다.

' Constant values from the "winuser.h" header file.
Friend Const WS_CHILD As Integer = &H40000000, WS_VISIBLE As Integer = &H10000000

Friend Shared Sub CreateHostHwnd(ByVal parentHwnd As IntPtr)
    ' Set up the parameters for the host hwnd.
    Dim parameters As New HwndSourceParameters("Visual Hit Test", _width, _height)
    parameters.WindowStyle = WS_VISIBLE Or WS_CHILD
    parameters.SetPosition(0, 24)
    parameters.ParentWindow = parentHwnd
    parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)

    ' Create the host hwnd for the visuals.
    myHwndSource = New HwndSource(parameters)

    ' Set the hwnd background color to the form's background color.
    myHwndSource.CompositionTarget.BackgroundColor = System.Windows.Media.Brushes.OldLace.Color
End Sub
// Constant values from the "winuser.h" header file.
internal const int WS_CHILD = 0x40000000,
                   WS_VISIBLE = 0x10000000;

internal static void CreateHostHwnd(IntPtr parentHwnd)
{
    // Set up the parameters for the host hwnd.
    HwndSourceParameters parameters = new HwndSourceParameters("Visual Hit Test", _width, _height);
    parameters.WindowStyle = WS_VISIBLE | WS_CHILD;
    parameters.SetPosition(0, 24);
    parameters.ParentWindow = parentHwnd;
    parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);

    // Create the host hwnd for the visuals.
    myHwndSource = new HwndSource(parameters);

    // Set the hwnd background color to the form's background color.
    myHwndSource.CompositionTarget.BackgroundColor = System.Windows.Media.Brushes.OldLace.Color;
}
참고참고

ExtendedWindowStyle 속성 값은 WS_EX_TRANSPARENT로 설정할 수 없습니다.즉, 호스트 Win32 창은 투명하게 만들 수 없습니다.이 때문에 호스트 Win32 창의 배경색은 부모 창과 동일한 배경색으로 설정됩니다.

호스트 Win32 창에 시각적 개체 추가

시각적 개체의 호스트 Win32 컨테이너 창을 만들면 창에 시각적 개체를 추가할 수 있습니다. 애니메이션과 같은 시각적 개체에 대한 변환이 호스트 Win32 창의 경계 사각형을 벗어나지 않도록 할 수 있습니다.

다음 예제에서는 HwndSource 개체를 만들어 여기에 시각적 개체를 추가하는 코드를 보여 줍니다.

참고참고

HwndSource 개체의 RootVisual 속성을 호스트 Win32 창에 추가하는 첫 번째 시각적 개체로 설정합니다.루트 시각적 개체는 시각적 개체 트리의 최상위 노드를 정의합니다.이후에 호스트 Win32 창에 추가하는 시각적 개체는 자식 개체로 추가됩니다.

Public Shared Sub CreateShape(ByVal parentHwnd As IntPtr)
    ' Create an instance of the shape.
    Dim myShape As New MyShape()

    ' Determine whether the host container window has been created.
    If myHwndSource Is Nothing Then
        ' Create the host container window for the visual objects.
        CreateHostHwnd(parentHwnd)

        ' Associate the shape with the host container window.
        myHwndSource.RootVisual = myShape
    Else
        ' Assign the shape as a child of the root visual.
        CType(myHwndSource.RootVisual, ContainerVisual).Children.Add(myShape)
    End If
End Sub
public static void CreateShape(IntPtr parentHwnd)
{
    // Create an instance of the shape.
    MyShape myShape = new MyShape();

    // Determine whether the host container window has been created.
    if (myHwndSource == null)
    {
        // Create the host container window for the visual objects.
        CreateHostHwnd(parentHwnd);

        // Associate the shape with the host container window.
        myHwndSource.RootVisual = myShape;
    }
    else
    {
        // Assign the shape as a child of the root visual.
        ((ContainerVisual)myHwndSource.RootVisual).Children.Add(myShape);
    }
}

Win32 메시지 필터 구현

시각적 개체용 호스트 Win32 창에는 응용 프로그램 큐에서 창으로 전송되는 메시지를 처리하기 위한 창 메시지 필터 프로시저가 필요합니다. 창 프로시저는 Win32 시스템에서 입력 메시지나 창 관리 메시지와 같은 메시지를 수신합니다. 원하는 경우 고유의 창 프로시저에서 메시지를 처리하거나 기본 처리를 위해 시스템에 메시지를 전달할 수 있습니다.

사용자가 시각적 개체의 부모로 정의한 HwndSource 개체는 사용자가 제공한 창 메시지 필터 프로시저를 참조해야 합니다. HwndSource 개체를 만들 때 창 프로시저를 참조하도록 HwndSourceHook 속성을 설정합니다.

parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)
parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);

다음 예제에서는 왼쪽 및 오른쪽 마우스 단추 해제 메시지를 처리하는 코드를 보여 줍니다. 마우스 적중 위치의 좌표 값은 lParam 매개 변수 값에 포함되어 있습니다.

' Constant values from the "winuser.h" header file.
Friend Const WM_LBUTTONUP As Integer = &H202, WM_RBUTTONUP As Integer = &H205

Friend Shared Function ApplicationMessageFilter(ByVal hwnd As IntPtr, ByVal message As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
    ' Handle messages passed to the visual.
    Select Case message
        ' Handle the left and right mouse button up messages.
        Case WM_LBUTTONUP, WM_RBUTTONUP
            Dim pt As New System.Windows.Point()
            pt.X = CUInt(lParam) And CUInt(&HFFFF) ' LOWORD = x
            pt.Y = CUInt(lParam) >> 16 ' HIWORD = y
            MyShape.OnHitTest(pt, message)
    End Select

    Return IntPtr.Zero
End Function
// Constant values from the "winuser.h" header file.
internal const int WM_LBUTTONUP = 0x0202,
                   WM_RBUTTONUP = 0x0205;

internal static IntPtr ApplicationMessageFilter(
    IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    // Handle messages passed to the visual.
    switch (message)
    {
        // Handle the left and right mouse button up messages.
        case WM_LBUTTONUP:
        case WM_RBUTTONUP:
            System.Windows.Point pt = new System.Windows.Point();
            pt.X = (uint)lParam & (uint)0x0000ffff;  // LOWORD = x
            pt.Y = (uint)lParam >> 16;               // HIWORD = y
            MyShape.OnHitTest(pt, message);
            break;
    }

    return IntPtr.Zero;
}

Win32 메시지 처리

다음 예제의 코드는 호스트 Win32 창에 포함된 시각적 개체의 계층 구조에 대해 적중 테스트를 수행하는 방법을 보여 줍니다. HitTest 메서드를 사용하여 루트 시각적 개체와 적중 테스트를 수행할 좌표 값을 지정하면 해당 지점이 시각적 개체의 기하 도형 안에 있는지 확인할 수 있습니다. 이 경우 루트 시각적 개체가 HwndSource 개체의 RootVisual 속성 값입니다.

        ' Constant values from the "winuser.h" header file.
        Public Const WM_LBUTTONUP As Integer = &H0202, WM_RBUTTONUP As Integer = &H0205

        ' Respond to WM_LBUTTONUP or WM_RBUTTONUP messages by determining which visual object was clicked.
        Public Shared Sub OnHitTest(ByVal pt As System.Windows.Point, ByVal msg As Integer)
            ' Clear the contents of the list used for hit test results.
            hitResultsList.Clear()

            ' Determine whether to change the color of the circle or to delete the shape.
            If msg = WM_LBUTTONUP Then
                MyWindow.changeColor = True
            End If
            If msg = WM_RBUTTONUP Then
                MyWindow.changeColor = False
            End If

            ' Set up a callback to receive the hit test results enumeration.
            VisualTreeHelper.HitTest(MyWindow.myHwndSource.RootVisual, Nothing, New HitTestResultCallback(AddressOf CircleHitTestResult), New PointHitTestParameters(pt))

            ' Perform actions on the hit test results list.
            If hitResultsList.Count > 0 Then
                ProcessHitTestResultsList()
            End If
        End Sub
// Constant values from the "winuser.h" header file.
public const int WM_LBUTTONUP = 0x0202,
                 WM_RBUTTONUP = 0x0205;

// Respond to WM_LBUTTONUP or WM_RBUTTONUP messages by determining which visual object was clicked.
public static void OnHitTest(System.Windows.Point pt, int msg)
{
    // Clear the contents of the list used for hit test results.
    hitResultsList.Clear();

    // Determine whether to change the color of the circle or to delete the shape.
    if (msg == WM_LBUTTONUP)
    {
        MyWindow.changeColor = true;
    }
    if (msg == WM_RBUTTONUP)
    {
        MyWindow.changeColor = false;
    }

    // Set up a callback to receive the hit test results enumeration.
    VisualTreeHelper.HitTest(MyWindow.myHwndSource.RootVisual,
                             null,
                             new HitTestResultCallback(CircleHitTestResult),
                             new PointHitTestParameters(pt));

    // Perform actions on the hit test results list.
    if (hitResultsList.Count > 0)
    {
        ProcessHitTestResultsList();
    }
}

시각적 개체에 적중 테스트를 수행하는 방법에 대한 자세한 내용은 시각적 계층에서 적중 테스트를 참조하십시오.

참고 항목

참조

HwndSource

개념

시각적 계층에서 적중 테스트

기타 리소스

Hit Test with Win32 Interoperation 샘플