Windows Presentation Foundation (WPF) は、アプリケーションを作成するための豊富な環境を提供します。 ただし、Win32 コードに多額の投資がある場合は、そのコードを完全に書き換えるのではなく、少なくとも一部のコードを WPF アプリケーションで再利用する方が効果的な場合があります。 WPF には、WPF ページで Win32 ウィンドウをホストするための簡単なメカニズムが用意されています。
このトピックでは、Win32 リスト ボックス コントロールをホストするアプリケーションである WPF サンプルでの Win32 ListBox コントロールのホストについて説明します。 この一般的な手順は、任意の Win32 ウィンドウをホストするように拡張できます。
要求事項
このトピックでは、WPF と Windows API の両方のプログラミングに関する基本的な知識を前提としています。 WPF プログラミングの基本的な概要については、「 作業の開始」を参照してください。 Windows API プログラミングの概要については、このテーマに関する多数の書籍、特に Charles Petzold による プログラミング Windows を参照してください。
このトピックに付属するサンプルは C# で実装されているため、プラットフォーム呼び出しサービス (PInvoke) を使用して Windows API にアクセスします。 PInvoke に関する知識は役に立ちますが、必須ではありません。
注
このトピックには、関連するサンプルのコード例が多数含まれています。 ただし、読みやすくするために、完全なサンプル コードは含まれていません。 WPF サンプルでの Win32 ListBox コントロールのホストから完全なコードを取得または表示できます。
基本的な手順
このセクションでは、WPF ページで Win32 ウィンドウをホストするための基本的な手順について説明します。 残りのセクションでは、各手順の詳細を確認します。
基本的なホスティング手順は次のとおりです。
ウィンドウをホストする WPF ページを実装します。 1 つの手法は、ホストされたウィンドウのページのセクションを予約する Border 要素を作成する方法です。
HwndHostから継承するコントロールをホストするクラスを実装します。
そのクラスで、 HwndHost クラス メンバー BuildWindowCoreをオーバーライドします。
ホストされたウィンドウを、WPF ページを含むウィンドウの子として作成します。 従来の WPF プログラミングでは明示的に使用する必要はありませんが、ホスティング ページはハンドル (HWND) を持つウィンドウです。
hwndParent
メソッドの BuildWindowCore パラメーターを通じて、ページ HWND を受け取ります。 ホストされるウィンドウは、この HWND の子として作成する必要があります。ホスト ウィンドウを作成したら、ホストされたウィンドウの HWND を返します。 1 つ以上の Win32 コントロールをホストする場合は、通常、HWND の子としてホスト ウィンドウを作成し、そのホスト ウィンドウのコントロールを子にします。 コントロールをホスト ウィンドウにラップすると、WPF ページがコントロールから通知を受け取る簡単な方法が提供されます。この方法では、HWND 境界を越えた通知に関する特定の Win32 の問題が処理されます。
子コントロールからの通知など、ホスト ウィンドウに送信された選択されたメッセージを処理します。 これを行うには 2 つの方法があります。
ホスティング クラスでメッセージを処理する場合は、WndProc クラスのHwndHost メソッドをオーバーライドします。
WPFにメッセージを処理させたい場合は、コードビハインドでイベントHwndHostクラスMessageHookを処理します。 このイベントは、ホストされたウィンドウによって受信されるすべてのメッセージに対して発生します。 このオプションを選択した場合でも、 WndProcをオーバーライドする必要がありますが、必要なのは最小限の実装だけです。
DestroyWindowCoreのWndProcメソッドとHwndHost メソッドをオーバーライドします。 HwndHost コントラクトを満たすためにこれらのメソッドをオーバーライドする必要がありますが、必要なのは最小限の実装のみである場合があります。
分離コード ファイルで、コントロール ホスティング クラスのインスタンスを作成し、ウィンドウをホストすることを目的とした Border 要素の子にします。
ホストされているウィンドウと通信するには、Microsoft Windows メッセージを送信し、子ウィンドウからのメッセージ (コントロールによって送信された通知など) を処理します。
ページ レイアウトを実装する
ListBox コントロールをホストする WPF ページのレイアウトは、2 つの領域で構成されます。 ページの左側には、Win32 コントロールを操作できるユーザー インターフェイス (UI) を提供するいくつかの WPF コントロールがホストされています。 ページの右上隅には、ホストされている ListBox コントロールの正方形の領域があります。
このレイアウトを実装するコードは非常に単純です。 ルート要素は、2 つの子要素を持つ DockPanel です。 1 つ目は、ListBox コントロールをホストする Border 要素です。 ページの右上隅にある 200 x 200 の正方形を占有します。 2 つ目は、情報を表示し、公開されている相互運用プロパティを設定して ListBox コントロールを操作できる WPF コントロールのセットを含む StackPanel 要素です。 StackPanelの子である各要素について、これらの要素が何であるか、何を行うかについて詳しく説明するために使用されるさまざまな要素の参照資料を参照してください。これらは以下のコード例に記載されていますが、ここでは説明しません (基本的な相互運用モデルではそれらを必要とせず、サンプルに対話機能を追加するために提供されています)。
<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 コントロールをホストするクラスを実装する
このサンプルの中核となるのは、ControlHost.csコントロールを実際にホストするクラスです。 HwndHostから継承されます。 コンストラクターは、高さと幅の 2 つのパラメーターを受け取ります。これは、ListBox コントロールをホストする Border 要素の高さと幅に対応します。 これらの値は、コントロールのサイズが Border 要素と一致することを確認するために後で使用されます。
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
定数のセットもあります。 これらの定数は主に Winuser.h から取得され、Win32 関数を呼び出すときに従来の名前を使用できます。
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
BuildWindowCore をオーバーライドして Microsoft Win32 ウィンドウを作成する
このメソッドをオーバーライドして、ページによってホストされる Win32 ウィンドウを作成し、ウィンドウとページ間の接続を確立します。 このサンプルには ListBox コントロールのホストが含まれているため、2 つのウィンドウが作成されます。 1 つ目は、WPF ページによって実際にホストされているウィンドウです。 ListBox コントロールは、そのウィンドウの子として作成されます。
この方法の理由は、コントロールから通知を受信するプロセスを簡略化するためです。 HwndHost クラスを使用すると、ホストしているウィンドウに送信されたメッセージを処理できます。 Win32 コントロールを直接ホストする場合は、コントロールの内部メッセージ ループに送信されたメッセージを受信します。 コントロールを表示してメッセージを送信することはできますが、コントロールが親ウィンドウに送信する通知は受け取りません。 つまり、特に、ユーザーがコントロールを操作するときに検出する方法はありません。 代わりに、ホスト ウィンドウを作成し、コントロールをそのウィンドウの子にします。 これにより、コントロールによって送信された通知を含むホスト ウィンドウのメッセージを処理できます。 便宜上、ホスト ウィンドウはコントロールの単純なラッパーに過しないので、パッケージは ListBox コントロールと呼ばれます。
ホスト ウィンドウと ListBox コントロールを作成する
PInvoke を使用して、ウィンドウ クラスを作成して登録することで、コントロールのホスト ウィンドウを作成できます。 ただし、より簡単な方法は、定義済みの "静的" ウィンドウ クラスを使用してウィンドウを作成することです。 これにより、コントロールから通知を受信するために必要なウィンドウ プロシージャが提供され、最小限のコーディングが必要になります。
コントロールの HWND は、読み取り専用プロパティを介して公開されます。これにより、ホスト ページはそれを使用してコントロールにメッセージを送信できます。
public IntPtr hwndListBox
{
get { return hwndControl; }
}
Public ReadOnly Property hwndListBox() As IntPtr
Get
Return hwndControl
End Get
End Property
ListBox コントロールは、ホスト ウィンドウの子として作成されます。 両方のウィンドウの高さと幅は、上で説明したコンストラクターに渡される値に設定されます。 これにより、ホスト ウィンドウとコントロールのサイズがページ上の予約領域と同じになります。 ウィンドウが作成されると、ホスト ウィンドウの HWND を含む HandleRef オブジェクトが返されます。
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 と WndProc を実装する
BuildWindowCoreに加えて、WndProcのDestroyWindowCoreメソッドとHwndHost メソッドもオーバーライドする必要があります。 この例では、コントロールのメッセージは MessageHook ハンドラーによって処理されるため、 WndProc と DestroyWindowCore の実装は最小限です。
WndProcの場合は、handled
を false
に設定して、メッセージが処理されていないことを示し、0 を返します。
DestroyWindowCoreの場合は、ウィンドウを破棄するだけです。
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
ページでコントロールをホストする
ページでコントロールをホストするには、まず、 ControlHost
クラスの新しいインスタンスを作成します。 コントロール (ControlHostElement
) を含む border 要素の高さと幅を、 ControlHost
コンストラクターに渡します。 これにより、ListBox のサイズが正しく設定されます。 次に、ControlHost
オブジェクトをホスト Childの Border プロパティに割り当てることで、ページ上でコントロールをホストします。
このサンプルでは、MessageHookのControlHost
イベントにハンドラーをアタッチして、コントロールからメッセージを受信します。 このイベントは、ホストされたウィンドウに送信されるすべてのメッセージに対して発生します。 この場合、これらは、コントロールからの通知を含む、実際の ListBox コントロールをラップするウィンドウに送信されるメッセージです。 このサンプルでは、SendMessage を呼び出してコントロールから情報を取得し、その内容を変更します。 ページがコントロールと通信する方法の詳細については、次のセクションで説明します。
注
SendMessage には 2 つの PInvoke 宣言があることに注意してください。 これは、 wParam
パラメーターを使用して文字列を渡し、もう 1 つは整数を渡すために使用するためです。 データが正しくマーシャリングされるようにするには、署名ごとに個別の宣言が必要です。
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
コントロールとページ間の通信を実装する
コントロールを操作する場合は、Windows メッセージを送信します。 コントロールは、ユーザーが操作を行うと、ホストウィンドウに通知を送って通知します。 WPF での Win32 ListBox コントロールのホストのサンプルには、このしくみのいくつかの例を示す UI が含まれています。
リストに項目を追加します。
選択した項目を一覧から削除する
現在選択されている項目のテキストを表示します。
リスト内の項目数を表示します。
ユーザーは、従来の Win32 アプリケーションの場合と同様に、リスト ボックス内の項目をクリックして選択することもできます。 ユーザーが項目を選択、追加、または挿入してリストボックスの状態を変更するたびに、表示されるデータは更新されます。
項目を追加するには、リスト ボックスに LB_ADDSTRING
メッセージを送信します。 アイテムを削除するには、 LB_GETCURSEL
を送信して現在の選択範囲のインデックスを取得し、 LB_DELETESTRING
してアイテムを削除します。 また、サンプルは LB_GETCOUNT
を送信し、返された値を使用して項目の数を示す表示を更新します。
SendMessage
のこれらの両方のインスタンスでは、前のセクションで説明した PInvoke 宣言のいずれかを使用します。
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 イベントを発生させます。 ハンドラーは、ホスト ウィンドウのメイン ウィンドウ プロシージャと同じ情報を受け取ります。 また、ブール値 ( handled
) への参照も渡します。
handled
をtrue
に設定して、メッセージを処理し、それ以上の処理は必要ないことを示します。
WM_COMMAND
はさまざまな理由で送信されるため、通知 ID を調べて、それが処理するイベントであるかどうかを判断する必要があります。 ID は、 wParam
パラメーターの上位ワードに含まれています。 このサンプルでは、ビット演算子を使用して ID を抽出します。 ユーザーが選択を行ったり変更したりした場合、ID は LBN_SELCHANGE
されます。
LBN_SELCHANGE
を受信すると、サンプルは、コントロールにLB_GETCURSEL
メッセージを送信することによって、選択した項目のインデックスを取得します。 テキストを取得するには、最初に StringBuilderを作成します。 次に、コントロールに LB_GETTEXT
メッセージを送信します。 空の StringBuilder オブジェクトを wParam
パラメーターとして渡します。
SendMessage
が返されると、StringBuilderには選択した項目のテキストが含まれます。 この SendMessage
の使用には、さらに別の PInvoke 宣言が必要です。
最後に、 handled
を true
に設定して、メッセージが処理されたことを示します。
こちらも参照ください
.NET Desktop feedback