チュートリアル: WPF での Win32 コントロールのホストWalkthrough: Hosting a Win32 Control in WPF

Windows Presentation Foundation (WPF) は、アプリケーションを作成するための豊富な環境を提供します。Windows Presentation Foundation (WPF) provides a rich environment for creating applications. ただし、Win32 コードのかなりの投資を存在する場合があります、少なくともいくつ再利用するより効果的なが、WPF アプリケーションでのコードではなく完全に書き換えます。However, when you have a substantial investment in Win32 code, it may be more effective to reuse at least some of that code in your WPF application rather than rewrite it completely. WPF には、WPF ページ上の Win32 ウィンドウをホストするための簡単なメカニズムが用意されています。WPF provides a straightforward mechanism for hosting a Win32 window, on a WPF page.

このトピックで説明するアプリケーション、 WPF のサンプルでの Win32 ListBox コントロールをホストしているWin32 のリスト ボックス コントロールがホストされます。This topic walks you through an application, Hosting a Win32 ListBox Control in WPF Sample, that hosts a Win32 list box control. この一般的な手順は、すべての Win32 ウィンドウのホスティングに拡張できます。This general procedure can be extended to hosting any Win32 window.

必要条件Requirements

このトピックでは、WPF と Windows API の両方のプログラミングの基礎知識を前提とします。This topic assumes a basic familiarity with both WPF and Windows API programming. WPF プログラミングに基本的な概要については、次を参照してください。 Getting Startedします。For a basic introduction to WPF programming, see Getting Started. Windows API のプログラミングの概要についてを参照してください、数多くの書籍の件名、特にプログラミング Windows Charles Petzold 著。For an introduction to Windows API programming, see any of the numerous books on the subject, in particular Programming Windows by Charles Petzold.

このトピックに付属するサンプルがで実装されているためC#、Windows API にアクセスするプラットフォーム呼び出しサービス (PInvoke) の使用します。Because the sample that accompanies this topic is implemented in C#, it makes use of Platform Invocation Services (PInvoke) to access the Windows API. PInvoke の知識は役立ちますが、必須ではありませんが。Some familiarity with PInvoke is helpful but not essential.

注意

このトピックには、関連するサンプルからのコード例の数が含まれます。This topic includes a number of code examples from the associated sample. しかし、読みやすくするため、完全なサンプル コードは含まれていません。However, for readability, it does not include the complete sample code. 取得するか、完全なコードを閲覧WPF のサンプルでの Win32 ListBox コントロールをホストしているします。You can obtain or view complete code from Hosting a Win32 ListBox Control in WPF Sample.

基本手順The Basic Procedure

このセクションでは、WPF ページ上の Win32 ウィンドウをホストするための基本的な手順について説明します。This section outlines the basic procedure for hosting a Win32 window on a WPF page. 残りのセクションでは、各手順の詳細を実行します。The remaining sections go through the details of each step.

基本的なホスティング手順です。The basic hosting procedure is:

  1. ウィンドウをホストする WPF ページを実装します。Implement a WPF page to host the window. 1 つの方法は、Borderにホストされたウィンドウのページのセクションを予約する要素。One technique is to create a Border element to reserve a section of the page for the hosted window.

  2. 継承するコントロールをホストするクラスを実装するHwndHostします。Implement a class to host the control that inherits from HwndHost.

  3. そのクラスでオーバーライド、HwndHostクラス メンバーBuildWindowCoreします。In that class, override the HwndHost class member BuildWindowCore.

  4. WPF ページを含むウィンドウの子としてホストされたウィンドウを作成します。Create the hosted window as a child of the window that contains the WPF page. 従来の WPF プログラミングが明示的に作成する必要はありませんが、それを使用して、ホスティング ページは、ウィンドウ ハンドル (HWND) を使用します。Although conventional WPF programming does not need to explicitly make use of it, the hosting page is a window with a handle (HWND). ページの HWND を受け取るを通じて、hwndParentのパラメーター、BuildWindowCoreメソッド。You receive the page HWND through the hwndParent parameter of the BuildWindowCore method. この HWND の子としてホストされたウィンドウを作成する必要があります。The hosted window should be created as a child of this HWND.

  5. ホスト ウィンドウを作成した後は、ホストされたウィンドウの HWND を返します。Once you have created the host window, return the HWND of the hosted window. 1 つまたは複数の Win32 コントロールをホストする場合を通常 HWND の子としてホスト ウィンドウを作成してそのホスト ウィンドウのコントロールの子。If you want to host one or more Win32 controls, you typically create a host window as a child of the HWND and make the controls children of that host window. ホスト ウィンドウで、コントロールをラップするには、HWND の境界にまたがっていくつか特定の Win32 問題の通知を処理する、コントロールから通知を受け取る WPF ページの簡単な方法が提供します。Wrapping the controls in a host window provides a simple way for your WPF page to receive notifications from the controls, which deals with some particular Win32 issues with notifications across the HWND boundary.

  6. 子コントロールからの通知など、ホスト ウィンドウに送信される選択したメッセージを処理します。Handle selected messages sent to the host window, such as notifications from child controls. これには、2 つの方法があります。There are two ways to do this.

    • ホストするクラスでのメッセージを処理する場合は、オーバーライド、WndProcのメソッド、HwndHostクラス。If you prefer to handle messages in your hosting class, override the WndProc method of the HwndHost class.

    • WPF のメッセージを処理、処理を行う場合、HwndHostクラスMessageHook分離コードでイベント。If you prefer to have the WPF handle the messages, handle the HwndHost class MessageHook event in your code-behind. このイベントは、ホストされたウィンドウで受信されるすべてのメッセージに対して発生します。This event occurs for every message that is received by the hosted window. まだをオーバーライドする必要がある場合、このオプションを選択すると、 WndProc、最小限の実装のみ必要しますが、あります。If you choose this option, you must still override WndProc, but you only need a minimal implementation.

  7. 上書き、DestroyWindowCoreWndProcメソッドのHwndHostします。Override the DestroyWindowCore and WndProc methods of HwndHost. 満たすためにこれらのメソッドをオーバーライドする必要があります、HwndHostコントラクトが最小限の実装を提供する必要がありますのみです。You must override these methods to satisfy the HwndHost contract, but you may only need to provide a minimal implementation.

  8. 分離コード ファイルで、コントロール ホスト クラスのインスタンスを作成しの子、Borderウィンドウをホストするためのものでは、要素。In your code-behind file, create an instance of the control hosting class and make it a child of the Border element that is intended to host the window.

  9. 送信することで、ホストされたウィンドウとの通信Microsoft WindowsMicrosoft Windowsメッセージとコントロールによる通知の送信など、その子ウィンドウからメッセージを処理します。Communicate with the hosted window by sending it Microsoft WindowsMicrosoft Windows messages and handling messages from its child windows, such as notifications sent by controls.

ページ レイアウトを実装します。Implement the Page Layout

ListBox コントロールをホストする WPF ページのレイアウトは、2 つのリージョンで構成されます。The layout for the WPF page that hosts the ListBox Control consists of two regions. ページの左側にあるホストを提供するいくつかの WPF コントロールをユーザー インターフェイス (UI)user interface (UI)Win32 コントロールを操作することができます。The left side of the page hosts several WPF controls that provide a ユーザー インターフェイス (UI)user interface (UI) that allows you to manipulate the Win32 control. ページの右上隅では、ホストされている ListBox コントロールの正方形の領域を持ちます。The upper right corner of the page has a square region for the hosted ListBox Control.

このレイアウトを実装するコードは簡単です。The code to implement this layout is quite simple. ルート要素は、DockPanelを持つ 2 つの子要素。The root element is a DockPanel that has two child elements. 1 つは、 Border ListBox コントロールをホストする要素。The first is a Border element that hosts the ListBox Control. 200 x 200 正方形インチのページの右上隅を占有します。It occupies a 200x200 square in the upper right corner of the page. 2 つ目は、StackPanel相互運用性のプロパティを公開する一連の情報を表示し、設定して、ListBox コントロールを操作する WPF コントロールを含む要素。The second is a StackPanel element that contains a set of WPF controls that display information and allow you to manipulate the ListBox Control by setting exposed interoperation properties. 各要素の子である、StackPanelの詳細については、これらの要素とは何かがどのように使用するさまざまな要素のリファレンスを参照してください、、これらは次のサンプル コードに表示がされません (基本的な以下の説明。相互運用のモデルは、これらのいずれかにも必要ありません、提供されるサンプルをいくつかの対話機能を追加する)。For each of the elements that are children of the StackPanel, see the reference material for the various elements used for details on what these elements are or what they do, these are listed in the example code below but will not be explained here (the basic interoperation model does not require any of them, they are provided to add some interactivity to the sample).

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="WPF_Hosting_Win32_Control.HostWindow"
  Name="mainWindow"
  Loaded="On_UIReady">

  <DockPanel Background="LightGreen">
    <Border Name="ControlHostElement"
    Width="200"
    Height="200"
    HorizontalAlignment="Right"
    VerticalAlignment="Top"
    BorderBrush="LightGray"
    BorderThickness="3"
    DockPanel.Dock="Right"/>
    <StackPanel>
      <Label HorizontalAlignment="Center"
        Margin="0,10,0,0"
        FontSize="14"
        FontWeight="Bold">Control the Control</Label>
      <TextBlock Margin="10,10,10,10" >Selected Text: <TextBlock  Name="selectedText"/></TextBlock>
      <TextBlock Margin="10,10,10,10" >Number of Items: <TextBlock  Name="numItems"/></TextBlock>
  
      <Line X1="0" X2="200"
        Stroke="LightYellow"
        StrokeThickness="2"
        HorizontalAlignment="Center"
        Margin="0,20,0,0"/>
  
      <Label HorizontalAlignment="Center"
        Margin="10,10,10,10">Append an Item to the List</Label>
      <StackPanel Orientation="Horizontal">
        <Label HorizontalAlignment="Left"
          Margin="10,10,10,10">Item Text</Label>
        <TextBox HorizontalAlignment="Left"
          Name="txtAppend"
          Width="200"
          Margin="10,10,10,10"></TextBox>
      </StackPanel>
  
      <Button HorizontalAlignment="Left"
        Click="AppendText"
        Width="75"
        Margin="10,10,10,10">Append</Button>

      <Line X1="0" X2="200"
        Stroke="LightYellow"
        StrokeThickness="2"
        HorizontalAlignment="Center"
        Margin="0,20,0,0"/>
  
      <Label HorizontalAlignment="Center"
        Margin="10,10,10,10">Delete the Selected Item</Label>
  
      <Button Click="DeleteText"
        Width="125"
        Margin="10,10,10,10"
        HorizontalAlignment="Left">Delete</Button>
    </StackPanel>
  </DockPanel>
</Window>  

Microsoft Win32 コントロールをホストするクラスを実装します。Implement a Class to Host the Microsoft Win32 Control

このサンプルのコアは、実際には、コントロール、ControlHost.cs をホストするクラスです。The core of this sample is the class that actually hosts the control, ControlHost.cs. 継承HwndHostします。It inherits from HwndHost. コンス トラクターは 2 つのパラメーター、高さと幅、高さと幅に対応する、 Border ListBox コントロールをホストする要素。The constructor takes two parameters, height and width, which correspond to the height and width of the Border element that hosts the ListBox control. コントロールの一致項目のサイズを確実にこれらの値は後で使用されて、Border要素。These values are used later to ensure that the size of the control matches the Border element.

public class ControlHost : HwndHost
{
  IntPtr hwndControl;
  IntPtr hwndHost;
  int hostHeight, hostWidth;

  public ControlHost(double height, double width)
  {
    hostHeight = (int)height;
    hostWidth = (int)width;
  }
Public Class ControlHost
    Inherits HwndHost
  Private hwndControl As IntPtr
  Private hwndHost As IntPtr
  Private hostHeight, hostWidth As Integer

  Public Sub New(ByVal height As Double, ByVal width As Double)
          hostHeight = CInt(height)
          hostWidth = CInt(width)
  End Sub

定数のセットもします。There is also a set of constants. これらの定数は大きく Winuser.h からのものし、Win32 関数を呼び出すときに、従来の名前を使用すること。These constants are largely taken from Winuser.h, and allow you to use conventional names when calling Win32 functions.

internal const int
  WS_CHILD = 0x40000000,
  WS_VISIBLE = 0x10000000,
  LBS_NOTIFY = 0x00000001,
  HOST_ID = 0x00000002,
  LISTBOX_ID = 0x00000001,
  WS_VSCROLL = 0x00200000,
  WS_BORDER = 0x00800000;
Friend Const WS_CHILD As Integer = &H40000000, WS_VISIBLE As Integer = &H10000000, LBS_NOTIFY As Integer = &H00000001, HOST_ID As Integer = &H00000002, LISTBOX_ID As Integer = &H00000001, WS_VSCROLL As Integer = &H00200000, WS_BORDER As Integer = &H00800000

Microsoft Win32 ウィンドウを作成する BuildWindowCore をオーバーライドします。Override BuildWindowCore to Create the Microsoft Win32 Window

Win32 ウィンドウ、ページによってホストされると、ウィンドウと、ページ間の接続を作成するには、このメソッドをオーバーライドするとします。You override this method to create the Win32 window that will be hosted by the page, and make the connection between the window and the page. このサンプルでは、ListBox コントロールのホストは、2 つのウィンドウが作成されます。Because this sample involves hosting a ListBox Control, two windows are created. 最初は、WPF ページによって実際にホストされているウィンドウです。The first is the window that is actually hosted by the WPF page. ListBox コントロールは、そのウィンドウの子として作成されます。The ListBox Control is created as a child of that window.

このアプローチの理由は、コントロールから通知を受信プロセスが簡略化です。The reason for this approach is to simplify the process of receiving notifications from the control. HwndHostクラスを使用してそれをホストしているウィンドウに送信されるメッセージを処理できます。The HwndHost class allows you to process messages sent to the window that it is hosting. Win32 ホストを直接制御する場合は、コントロールの内部メッセージ ループに送信されるメッセージが表示されます。If you host a Win32 control directly, you receive the messages sent to the internal message loop of the control. メッセージを送信、コントロールを表示できますが、コントロールの親ウィンドウに送信される通知は表示されません。You can display the control and send it messages, but you do not receive the notifications that the control sends to its parent window. この、特に、ことがないということ、ユーザーがコントロールと対話するときの検出方法です。This means, among other things, that you have no way of detecting when the user interacts with the control. 代わりに、ホスト ウィンドウを作成し、そのウィンドウの子コントロールを作成します。Instead, create a host window and make the control a child of that window. これにより、コントロールによって送信された通知など、ホスト ウィンドウのメッセージを処理することができます。This allows you to process the messages for the host window including the notifications sent to it by the control. 便宜上、ホスト ウィンドウは少し上回る、コントロールの単純なラッパーであるため、パッケージは参照に ListBox コントロールとして。For convenience, since the host window is little more than a simple wrapper for the control, the package will be referred to as a ListBox control.

ホスト ウィンドウとリスト ボックス コントロールを作成します。Create the Host Window and ListBox Control

PInvoke を使用して、ウィンドウ クラスの登録を作成してコントロールのホスト ウィンドウを作成して、具合ことができます。You can use PInvoke to create a host window for the control by creating and registering a window class, and so on. ただし、はるかに簡単な方法は、定義済みの「静的」ウィンドウ クラスを使用してウィンドウを作成します。However, a much simpler approach is to create a window with the predefined "static" window class. これにより、ウィンドウ プロシージャし、コントロールから通知を受信するために必要最小限のコーディングが必要です。This provides you with the window procedure you need in order to receive notifications from the control, and requires minimal coding.

コントロールの HWND は、ホスト ページを使用すると、コントロールにメッセージを送信使用できるように、読み取り専用プロパティを通じて公開されます。The HWND of the control is exposed through a read-only property, such that the host page can use it to send messages to the control.

public IntPtr hwndListBox
{
  get { return hwndControl; }
}
Public ReadOnly Property hwndListBox() As IntPtr
  Get
      Return hwndControl
  End Get
End Property

ListBox コントロールは、ホスト ウィンドウの子として作成されます。The ListBox control is created as a child of the host window. 両方のウィンドウの幅と高さは、前に説明した、コンス トラクターに渡される値に設定されます。The height and width of both windows are set to the values passed to the constructor, discussed above. これにより、ホスト ウィンドウとコントロールのサイズは、ページ上の予約済み領域と同じです。This ensures that the size of the host window and control is identical to the reserved area on the page. サンプルを返します、windows が作成された後、HandleRefホスト ウィンドウの HWND を含むオブジェクト。After the windows are created, the sample returns a HandleRef object that contains the HWND of the host window.

protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
  hwndControl = IntPtr.Zero;
  hwndHost = IntPtr.Zero;

  hwndHost = CreateWindowEx(0, "static", "",
                            WS_CHILD | WS_VISIBLE,
                            0, 0,
                            hostWidth, hostHeight, 
                            hwndParent.Handle,
                            (IntPtr)HOST_ID,
                            IntPtr.Zero,
                            0);

  hwndControl = CreateWindowEx(0, "listbox", "",
                                WS_CHILD | WS_VISIBLE | LBS_NOTIFY
                                  | WS_VSCROLL | WS_BORDER,
                                0, 0,
                                hostWidth, hostHeight, 
                                hwndHost,
                                (IntPtr) LISTBOX_ID,
                                IntPtr.Zero,
                                0);

  return new HandleRef(this, hwndHost);
}
Protected Overrides Function BuildWindowCore(ByVal hwndParent As HandleRef) As HandleRef
  hwndControl = IntPtr.Zero
  hwndHost = IntPtr.Zero

  hwndHost = CreateWindowEx(0, "static", "", WS_CHILD Or WS_VISIBLE, 0, 0, hostWidth, hostHeight, hwndParent.Handle, New IntPtr(HOST_ID), IntPtr.Zero, 0)

  hwndControl = CreateWindowEx(0, "listbox", "", WS_CHILD Or WS_VISIBLE Or LBS_NOTIFY Or WS_VSCROLL Or WS_BORDER, 0, 0, hostWidth, hostHeight, hwndHost, New IntPtr(LISTBOX_ID), IntPtr.Zero, 0)

  Return New HandleRef(Me, hwndHost)
End Function
//PInvoke declarations
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
                                              string lpszClassName,
                                              string lpszWindowName,
                                              int style,
                                              int x, int y,
                                              int width, int height,
                                              IntPtr hwndParent,
                                              IntPtr hMenu,
                                              IntPtr hInst,
                                              [MarshalAs(UnmanagedType.AsAny)] object pvParam);
'PInvoke declarations
<DllImport("user32.dll", EntryPoint := "CreateWindowEx", CharSet := CharSet.Unicode)>
Friend Shared Function CreateWindowEx(ByVal dwExStyle As Integer, ByVal lpszClassName As String, ByVal lpszWindowName As String, ByVal style As Integer, ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal hwndParent As IntPtr, ByVal hMenu As IntPtr, ByVal hInst As IntPtr, <MarshalAs(UnmanagedType.AsAny)> ByVal pvParam As Object) As IntPtr
End Function

実装 DestroyWindow と WndProcImplement DestroyWindow and WndProc

ほかにBuildWindowCore、オーバーライドすることも必要があります、WndProcDestroyWindowCoreのメソッド、HwndHostします。In addition to BuildWindowCore, you must also override the WndProc and DestroyWindowCore methods of the HwndHost. によって、この例では、コントロールのメッセージの処理、MessageHookハンドラーの実装ではそのためWndProcDestroyWindowCoreは最小限です。In this example, the messages for the control are handled by the MessageHook handler, thus the implementation of WndProc and DestroyWindowCore is minimal. 場合にWndProc設定handledfalseをメッセージが処理されないことを示す 0 を返します。In the case of WndProc, set handled to false to indicate that the message was not handled and return 0. DestroyWindowCore、単にウィンドウを破棄します。For DestroyWindowCore, simply destroy the window.

protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
  handled = false;
  return IntPtr.Zero;
}

protected override void DestroyWindowCore(HandleRef hwnd)
{
  DestroyWindow(hwnd.Handle);
}
Protected Overrides Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
  handled = False
  Return IntPtr.Zero
End Function

Protected Overrides Sub DestroyWindowCore(ByVal hwnd As HandleRef)
  DestroyWindow(hwnd.Handle)
End Sub
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
<DllImport("user32.dll", EntryPoint := "DestroyWindow", CharSet := CharSet.Unicode)>
Friend Shared Function DestroyWindow(ByVal hwnd As IntPtr) As Boolean
End Function

ページ上のコントロールをホストします。Host the Control on the Page

新しいインスタンスの作成最初のページへのコントロールをホストする、ControlHostクラス。To host the control on the page, you first create a new instance of the ControlHost class. コントロールを含む border 要素の幅と高さを渡します (ControlHostElement) に、ControlHostコンス トラクター。Pass the height and width of the border element that contains the control (ControlHostElement) to the ControlHost constructor. これにより、リスト ボックスのサイズが正しくなります。This ensures that the ListBox is sized correctly. 割り当てることで、ページ上のコントロールをホストする、ControlHostオブジェクトをChildホストのプロパティBorderします。You then host the control on the page by assigning the ControlHost object to the Child property of the host Border.

サンプルにはハンドラーをMessageHookのイベント、ControlHostコントロールからメッセージを受信します。The sample attaches a handler to the MessageHook event of the ControlHost to receive messages from the control. このイベントは、ホストされたウィンドウに送信されるすべてのメッセージに対して発生します。This event is raised for every message sent to the hosted window. ここでは、これらは、コントロールからの通知など、実際の ListBox コントロールをラップするウィンドウに送信されるメッセージです。In this case, these are the messages sent to window that wraps the actual ListBox control, including notifications from the control. サンプルでは、コントロールから情報を取得し、その内容を変更する 1 つを呼び出します。The sample calls SendMessage to obtain information from the control and modify its contents. ページが、コントロールと通信する方法の詳細については、次のセクションで説明します。The details of how the page communicates with the control are discussed in the next section.

注意

SendMessage の 2 つの PInvoke 宣言があることに注意してください。Notice that there are two PInvoke declarations for SendMessage. これは、1 つを使用しているため、wParam文字列と、その他に渡すパラメーターは整数を渡す使用します。This is necessary because one uses the wParam parameter to pass a string and the other uses it to pass an integer. データが正しくマーシャ リングすることを確認するには、各署名の別の宣言する必要があります。You need a separate declaration for each signature to ensure that the data is marshaled correctly.

public partial class HostWindow : Window
{
int selectedItem;
IntPtr hwndListBox;
ControlHost listControl;
Application app;
Window myWindow;
int itemCount;

private void On_UIReady(object sender, EventArgs e)
{
  app = System.Windows.Application.Current;
  myWindow = app.MainWindow;
  myWindow.SizeToContent = SizeToContent.WidthAndHeight;
  listControl = new ControlHost(ControlHostElement.ActualHeight, ControlHostElement.ActualWidth);
  ControlHostElement.Child = listControl;
  listControl.MessageHook += new HwndSourceHook(ControlMsgFilter);
  hwndListBox = listControl.hwndListBox;
  for (int i = 0; i < 15; i++) //populate listbox
  {
    string itemText = "Item" + i.ToString();
    SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, itemText);
  }
  itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
  numItems.Text = "" +  itemCount.ToString();
}
Partial Public Class HostWindow
    Inherits Window
    Private selectedItem As Integer
    Private hwndListBox As IntPtr
    Private listControl As ControlHost
    Private app As Application
    Private myWindow As Window
    Private itemCount As Integer

    Private Sub On_UIReady(ByVal sender As Object, ByVal e As EventArgs)
        app = System.Windows.Application.Current
        myWindow = app.MainWindow
        myWindow.SizeToContent = SizeToContent.WidthAndHeight
        listControl = New ControlHost(ControlHostElement.ActualHeight, ControlHostElement.ActualWidth)
        ControlHostElement.Child = listControl
        AddHandler listControl.MessageHook, AddressOf ControlMsgFilter
        hwndListBox = listControl.hwndListBox
        For i As Integer = 0 To 14 'populate listbox
            Dim itemText As String = "Item" & i.ToString()
            SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, itemText)
        Next i
        itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
        numItems.Text = "" & itemCount.ToString()
    End Sub

private IntPtr ControlMsgFilter(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
  int textLength;

  handled = false;
  if (msg == WM_COMMAND)
  {
    switch ((uint)wParam.ToInt32() >> 16 & 0xFFFF) //extract the HIWORD
    {
      case LBN_SELCHANGE : //Get the item text and display it
        selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero);
        textLength = SendMessage(listControl.hwndListBox, LB_GETTEXTLEN, IntPtr.Zero, IntPtr.Zero);
        StringBuilder itemText = new StringBuilder();
        SendMessage(hwndListBox, LB_GETTEXT, selectedItem, itemText);
        selectedText.Text = itemText.ToString();
        handled = true;
        break;
    }
  }
  return IntPtr.Zero;
}
internal const int
  LBN_SELCHANGE = 0x00000001,
  WM_COMMAND = 0x00000111,
  LB_GETCURSEL = 0x00000188,
  LB_GETTEXTLEN = 0x0000018A,
  LB_ADDSTRING = 0x00000180, 
  LB_GETTEXT = 0x00000189,
  LB_DELETESTRING = 0x00000182,
  LB_GETCOUNT = 0x0000018B;

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
                                       int msg,
                                       IntPtr wParam,
                                       IntPtr lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
                                       int msg,
                                       int wParam, 
                                       [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hwnd,
                                          int msg,
                                          IntPtr wParam,
                                          String lParam);

Private Function ControlMsgFilter(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
    Dim textLength As Integer

    handled = False
    If msg = WM_COMMAND Then
        Select Case CUInt(wParam.ToInt32()) >> 16 And &HFFFF 'extract the HIWORD
            Case LBN_SELCHANGE 'Get the item text and display it
                selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero)
                textLength = SendMessage(listControl.hwndListBox, LB_GETTEXTLEN, IntPtr.Zero, IntPtr.Zero)
                Dim itemText As New StringBuilder()
                SendMessage(hwndListBox, LB_GETTEXT, selectedItem, itemText)
                selectedText.Text = itemText.ToString()
                handled = True
        End Select
    End If
    Return IntPtr.Zero
End Function
Friend Const LBN_SELCHANGE As Integer = &H1, WM_COMMAND As Integer = &H111, LB_GETCURSEL As Integer = &H188, LB_GETTEXTLEN As Integer = &H18A, LB_ADDSTRING As Integer = &H180, LB_GETTEXT As Integer = &H189, LB_DELETESTRING As Integer = &H182, LB_GETCOUNT As Integer = &H18B

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As StringBuilder) As Integer
End Function

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As String) As IntPtr
End Function

コントロールと、ページ間の通信を実装します。Implement Communication Between the Control and the Page

Windows メッセージを送信することで、コントロールを操作します。You manipulate the control by sending it Windows messages. コントロールは、ユーザーがそのホスト ウィンドウに通知を送信することによってこれと対話するときに通知します。The control notifies you when the user interacts with it by sending notifications to its host window. WPF での Win32 ListBox コントロールをホストしているサンプルには、この動作のいくつかの例を提供する UI が用意されています。The Hosting a Win32 ListBox Control in WPF sample includes a UI that provides several examples of how this works:

  • リストに項目を追加します。Append an item to the list.

  • 一覧から選択した項目を削除します。Delete the selected item from the list

  • 現在選択されている項目のテキストを表示します。Display the text of the currently selected item.

  • 一覧で項目の数を表示します。Display the number of items in the list.

ユーザー選択もできます項目、リスト ボックスをクリックして、従来の Win32 アプリケーションのと同様。The user can also select an item in the list box by clicking on it, just as they would for a conventional Win32 application. 表示されるデータは、項目を追加するかを選択すると、追加すると、によって、ユーザーがリスト ボックスの状態を変更するたびが更新されます。The displayed data is updated each time the user changes the state of the list box by selecting, adding, or appending an item.

項目を追加するリスト ボックスの送信、 LB_ADDSTRINGメッセージします。To append items, send the list box an LB_ADDSTRING message. 項目を削除する送信 LB_GETCURSEL 現在の選択範囲のインデックスを取得し、 LB_DELETESTRING アイテムを削除します。To delete items, send LB_GETCURSEL to get the index of the current selection and then LB_DELETESTRING to delete the item. また、サンプルが送信され LB_GETCOUNT 、返される値を使用して、項目の数を示す表示を更新するとします。The sample also sends LB_GETCOUNT, and uses the returned value to update the display that shows the number of items. これら両方のインスタンスの SendMessage 前のセクションで説明されている PInvoke 宣言のいずれかを使用します。Both these instances of SendMessage use one of the PInvoke declarations discussed in the previous section.

private void AppendText(object sender, EventArgs args)
{
  if (!string.IsNullOrEmpty(txtAppend.Text))
  {
    SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, txtAppend.Text);
  }
  itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
  numItems.Text = "" + itemCount.ToString();
}
private void DeleteText(object sender, EventArgs args)
{
  selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero);
  if (selectedItem != -1) //check for selected item
  {
    SendMessage(hwndListBox, LB_DELETESTRING, (IntPtr)selectedItem, IntPtr.Zero);
  }
  itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
  numItems.Text = "" + itemCount.ToString();
}
Private Sub AppendText(ByVal sender As Object, ByVal args As EventArgs)
    If txtAppend.Text <> String.Empty Then
        SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, txtAppend.Text)
    End If
    itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
    numItems.Text = "" & itemCount.ToString()
End Sub
Private Sub DeleteText(ByVal sender As Object, ByVal args As EventArgs)
    selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero)
    If selectedItem <> -1 Then 'check for selected item
        SendMessage(hwndListBox, LB_DELETESTRING, New IntPtr(selectedItem), IntPtr.Zero)
    End If
    itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
    numItems.Text = "" & itemCount.ToString()
End Sub

ユーザーは、項目を選択するか、その選択を変更、コントロールはホスト ウィンドウを送信することで通知をWM_COMMANDメッセージを発生させる、MessageHookページのイベント。When the user selects an item or changes their selection, the control notifies the host window by sending it a WM_COMMAND message, which raises the MessageHook event for the page. ハンドラーは、ホスト ウィンドウのメイン ウィンドウ プロシージャと同じ情報を受け取ります。The handler receives the same information as the main window procedure of the host window. また、ブール値への参照を渡しますhandledします。It also passes a reference to a Boolean value, handled. 設定するhandledtrueをメッセージを処理して、それ以上の処理が必要なことを示します。You set handled to true to indicate that you have handled the message and no further processing is needed.

WM_COMMAND イベントを処理するかどうかを判断する通知 ID を調べる必要がありますので、さまざまな理由から、送信されます。WM_COMMAND is sent for a variety of reasons, so you must examine the notification ID to determine whether it is an event that you wish to handle. 上位ワードに ID が含まれている、wParamパラメーター。The ID is contained in the high word of the wParam parameter. このサンプルでは、ビットごとの演算子を使用して ID を抽出The sample uses bitwise operators to extract the ID. ユーザーが行われたまたは、自分の選択を変更する場合、ID になります LBN_SELCHANGEします。If the user has made or changed their selection, the ID will be LBN_SELCHANGE.

ときに LBN_SELCHANGE が受信されると、サンプル インデックスを取得、選択した項目のコントロールを送信することによって、 LB_GETCURSELメッセージします。When LBN_SELCHANGE is received, the sample gets the index of the selected item by sending the control a LB_GETCURSEL message. 作成する最初のテキストを取得する、StringBuilderします。To get the text, you first create a StringBuilder. コントロールを送信、 LB_GETTEXTメッセージします。You then send the control an LB_GETTEXT message. 空の渡すStringBuilderオブジェクトとして、wParamパラメーター。Pass the empty StringBuilder object as the wParam parameter. ときに SendMessage から制御が戻る、StringBuilder選択された項目のテキストが含まれます。When SendMessage returns, the StringBuilder will contain the text of the selected item. このように使用 SendMessage もう 1 つの PInvoke 宣言が必要です。This use of SendMessage requires yet another PInvoke declaration.

最後に、設定handledtrueをメッセージが処理されたことを示します。Finally, set handled to true to indicate that the message has been handled.

関連項目See also