ShowDialog가 아니라 표시 특성을 true로 설정하여 표시되는 양식이 있습니다. 이것은 드롭 다운처럼 동작합니다..NET 및 Windows Forms에서 마우스 후크로 이상한 동작이 발생했습니다.
이 양식은 SetWindowsHookEx(WH_MOUSE, ...)
을 사용하여 마우스 훅을 설치합니다.
마우스를 드롭 다운 바깥에서 클릭하면 내 HookProc
메서드에서 1을 반환하고 드롭 다운을 닫습니다.
이상한 점은 내 드롭 다운을 텍스트 상자로 클릭하면 내 HookProc
메서드로 처리되었지만 드롭 다운이 닫힌 후에도 텍스트 상자에 마우스 클릭이 계속 수신된다는 것입니다.
낯선 사람이 ... 레이블이나 단추를 클릭하면 드롭 다운이 끝난 후 예상대로 마우스 클릭을받지 못합니다!
어떤 일이 벌어지고 있는지 알 수 있습니까?
ETA 2 : 추가 조사에, 나는이 행동 유형 양식 드롭 다운을 구현하는 적어도 하나의 프레임 워크 제어에 전시되어 있음을 발견했습니다 때문에
당신은 내 모든 코드 아래 무시할 수 있습니다.
복제하려면 양식을 만들고 속성 표, 단추, 텍스트 상자 및 레이블을 추가하십시오. 속성 격자의 선택된 객체를 글꼴로 설정하십시오.
폼을 실행하고 글꼴 이름을 선택하십시오. 드롭 다운 목록이 나타납니다. 이제 양식의 텍스트 상자를 클릭하십시오. 텍스트 상자 클릭 이벤트가 발생합니다. 그러나 단추 또는 레이블도 이와 동일하지 않습니다.
무슨 일 이니?
ETA 1 : 여기
는 무슨 일이 일어나고 있는지 설명하기 How to set a Windows hook in Visual C# .NET 일부 빈약 한 코드입니다. 나는 변환기를 사용하여 코드를 다시 C#으로 변환했지만 잘하면 좋다. 확실하지 않지만 Console.WriteLine
을 Debug.WriteLine
으로 바꿔야 할 수 있습니다.
Form1
및 DropDown
의 두 가지 양식을 만듭니다.
(1) Form1
에서 VB.NET
하는 버튼, 레이블 및 텍스트 상자, 다음과 같은 코드를 추가합니다.
Imports System.Runtime.InteropServices
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Console.WriteLine("Button1_Click")
Dim dd As New DropDown
dd.Visible = True
Do While dd.Visible
Application.DoEvents()
MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 250, &HFF, 4)
Loop
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True)> _
Public Shared Function MsgWaitForMultipleObjectsEx(ByVal nCount As Integer, ByVal pHandles As IntPtr, ByVal dwMilliseconds As Integer, ByVal dwWakeMask As Integer, ByVal dwFlags As Integer) As Integer
End Function
Private Sub Label1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Label1.Click
Console.WriteLine("Label1_Click")
End Sub
Private Sub TextBox1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.Click
Console.WriteLine("TextBox1_Click")
End Sub
End Class
DropDown에서 다음 코드를 삽입하십시오. 배치, 다음 코드 드롭 다운에
using System.Runtime.InteropServices;
public class Form1
{
public Form1()
{
InitializeComponent();
Button1.Click += Button1_Click;
Label1.Click += Label1_Click;
TextBox1.Click += TextBox1_Click;
}
private void Button1_Click(System.Object sender, System.EventArgs e)
{
Console.WriteLine("Button1_Click");
DropDown dd = new DropDown();
dd.Visible = true;
while (dd.Visible) {
Application.DoEvents();
MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 250, 0xff, 4);
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int MsgWaitForMultipleObjectsEx(int nCount, IntPtr pHandles, int dwMilliseconds, int dwWakeMask, int dwFlags);
private void Label1_Click(object sender, System.EventArgs e)
{
Console.WriteLine("Label1_Click");
}
private void TextBox1_Click(object sender, System.EventArgs e)
{
Console.WriteLine("TextBox1_Click");
}
}
:
using System.Runtime.InteropServices;
public class DropDown
{
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
private int hHook = 0;
public const int WH_MOUSE = 7;
private HookProc MouseHookProcedure;
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct
{
public POINT pt;
public int hwnd;
public int wHitTestCode;
public int dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
protected override void OnDeactivate(System.EventArgs e)
{
base.OnDeactivate(e);
UnhookWindowsHookEx(hHook);
hHook = 0;
}
public DropDown()
{
InitializeComponent();
MouseHookProcedure = new HookProc(MouseHookProc);
hHook = SetWindowsHookEx(WH_MOUSE, MouseHookProcedure, new IntPtr(0), AppDomain.GetCurrentThreadId());
}
public int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
if (nCode < 0) {
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
else {
switch ((int)wParam) {
case 0x21:
case 0xa1:
case 0xa4:
case 0x204:
case 0x207:
case 0xa7:
case 0x201:
this.Visible = false;
return 1;
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
}
을에 Button, 레이블 및 텍스트 상자, 다음과 같은 코드를 추가를 Form1에
Imports System.Runtime.InteropServices
Public Class DropDown
Public Delegate Function HookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Private hHook As Integer = 0
Public Const WH_MOUSE As Integer = 7
Private MouseHookProcedure As HookProc
<StructLayout(LayoutKind.Sequential)> _
Public Class POINT
Public x As Integer
Public y As Integer
End Class
<StructLayout(LayoutKind.Sequential)> _
Public Class MouseHookStruct
Public pt As POINT
Public hwnd As Integer
Public wHitTestCode As Integer
Public dwExtraInfo As Integer
End Class
<DllImport("user32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As HookProc, ByVal hInstance As IntPtr, ByVal threadId As Integer) As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
Protected Overrides Sub OnDeactivate(ByVal e As System.EventArgs)
MyBase.OnDeactivate(e)
UnhookWindowsHookEx(hHook)
hHook = 0
End Sub
Public Sub New()
InitializeComponent()
MouseHookProcedure = New HookProc(AddressOf MouseHookProc)
hHook = SetWindowsHookEx(WH_MOUSE, MouseHookProcedure, New IntPtr(0), AppDomain.GetCurrentThreadId())
End Sub
Public Function MouseHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Dim MyMouseHookStruct As MouseHookStruct = DirectCast(Marshal.PtrToStructure(lParam, GetType(MouseHookStruct)), MouseHookStruct)
If nCode < 0 Then
Return CallNextHookEx(hHook, nCode, wParam, lParam)
Else
Select Case CInt(wParam)
Case &H21, &HA1, &HA4, &H204, &H207, &HA7, &H201
Me.Visible = False
Return 1
End Select
Return CallNextHookEx(hHook, nCode, wParam, lParam)
End If
End Function
End Class
(2) C#을
안녕하세요. 나는 IMessageFilter에 대해 들어 본 적이 없었는데, 그것은 나를위한 후킹을 돌보는 것처럼 보입니다. 기존 코드를 IMessageFilter로 대체하려고했지만 문제가 발생했습니다. 내 드롭 다운과 관련이없는 이벤트를 무시하기 위해 이벤트를 활성화 및 비활성화하는 드롭 다운에서 후크 앤 언 후크를 사용했습니다. 그러나 PreFilterMessage 전에 Deactivate가 발생합니다. PreFilterMessage를 사용하여 클릭 한 컨트롤과 해당 컨트롤이 속한 폼을 결정할 수 있습니다. 드롭 다운 후 해당 양식이 작성되었는지 어떻게 확인할 수 있습니까? – Jules
나는 그것을 할 방법이 있을지도 모른다. 먼저 드롭 다운을 표시하기 직전에 열려있는 모든 폼의 목록을 가져옵니다. PreFiltureMessage에서 클릭 된 컨트롤이 저장된 컬렉션의 폼에 속한 경우 클릭을 처리하고 드롭 다운을 닫습니다. 그렇지 않으면 무시합니다. – Jules
위의 내 drivel 무시합니다. IMessageFilter와 반대로 내 후크를 고수하기로 결정했습니다. 마우스 업 이벤트 필터를 추가하면 내 문제가 해결되었습니다. 다시 한번 감사드립니다. – Jules