2012-04-29 2 views
0

Я использую следующий класс here, чтобы подключить комбинацию клавиш по всему миру в приложении.Клавиатура Крючок замораживает клавиатуру, а приложение выполняет другую задачу

Imports System.Runtime.InteropServices 

Public Class KeyboardHook 

<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _ 
Private Overloads Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal HookProc As KBDLLHookProc, ByVal hInstance As IntPtr, ByVal wParam As Integer) As Integer 
End Function 
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _ 
Private Overloads Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer 
End Function 
<DllImport("User32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _ 
Private Overloads Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean 
End Function 

<StructLayout(LayoutKind.Sequential)> _ 
Private Structure KBDLLHOOKSTRUCT 
    Public vkCode As UInt32 
    Public scanCode As UInt32 
    Public flags As KBDLLHOOKSTRUCTFlags 
    Public time As UInt32 
    Public dwExtraInfo As UIntPtr 
End Structure 

<Flags()> _ 
Private Enum KBDLLHOOKSTRUCTFlags As UInt32 
    LLKHF_EXTENDED = &H1 
    LLKHF_INJECTED = &H10 
    LLKHF_ALTDOWN = &H20 
    LLKHF_UP = &H80 
End Enum 

Public Shared Event KeyDown(ByVal Key As Keys) 
Public Shared Event KeyUp(ByVal Key As Keys) 

Private Const WH_KEYBOARD_LL As Integer = 13 
Private Const HC_ACTION As Integer = 0 
Private Const WM_KEYDOWN = &H100 
Private Const WM_KEYUP = &H101 
Private Const WM_SYSKEYDOWN = &H104 
Private Const WM_SYSKEYUP = &H105 

Private Delegate Function KBDLLHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer 

Private KBDLLHookProcDelegate As KBDLLHookProc = New KBDLLHookProc(AddressOf KeyboardProc) 
Private HHookID As IntPtr = IntPtr.Zero 

Private Function KeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer 
    If (nCode = HC_ACTION) Then 
     Dim struct As KBDLLHOOKSTRUCT 
     Select Case wParam 
      Case WM_KEYDOWN, WM_SYSKEYDOWN 
       RaiseEvent KeyDown(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys)) 
      Case WM_KEYUP, WM_SYSKEYUP 
       RaiseEvent KeyUp(CType(CType(Marshal.PtrToStructure(lParam, struct.GetType()), KBDLLHOOKSTRUCT).vkCode, Keys)) 
     End Select 
    End If 
    Return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam) 
End Function 

Public Sub New() 
    HHookID = SetWindowsHookEx(WH_KEYBOARD_LL, KBDLLHookProcDelegate, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0) 
    If HHookID = IntPtr.Zero Then 
     Throw New Exception("Could not set keyboard hook") 
    End If 
End Sub 

Protected Overrides Sub Finalize() 
    If Not HHookID = IntPtr.Zero Then 
     UnhookWindowsHookEx(HHookID) 
    End If 
    MyBase.Finalize() 
End Sub 

End Class 

Работает хорошо, даже если приложение имеет фокус или нет, но у меня есть проблема. Моя заявка используется

My.Computer.Network.UploadFile 

Во время загрузки ход кайпорта перестает отвечать. Мышь в порядке.

Как сохранить клавиатуру в ходе других операций внутри приложения?

ответ

0

Да, это требует неприятностей. Windows может вызвать вызов метода обратного вызова, когда ваша программа перекачивает контур сообщения. Для Windows нет другого механизма, позволяющего сделать вызов в вашем основном потоке, не вызывая серьезных проблем с повторным подключением.

Это перестает работать, когда основной поток отключается, делая что-то еще, например, загружая файл. Это общее требование для приложений GUI, занимающих основной поток пользовательского интерфейса с другими задачами, делает пользовательский интерфейс кататоническим. Он перестает отвечать на вход и останавливает рисование. Через пару секунд оконный менеджер Windows запустит и заменит ваше главное окно «окном-призраком» с «Не реагировать» в строке заголовка. Вы получаете свой нос, втираемый в него сложнее, потому что теперь он также останавливает любой ввод на клавиатуре от обработки, Окно не может вызвать обратный вызов крючка.

Необходимо выполнить длительные задачи в другом потоке, чтобы поток пользовательского интерфейса мог оставаться отзывчивым. Или в конкретном случае, о котором вы говорите, вместо этого используйте UploadFileAsync().

+0

Я пошел и получил источник примера отсюда: [Пример MSDN] (http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx) ... проблема в том, что У меня есть загрузка в компоненте таймера. Перед загрузкой приложения фиксируется часть экрана и сохраняется в jpg. проблема с async теперь заключается в том, что иногда иногда срабатывает gdi + excpetion .... – e4rthdog

+0

Я не знаю, что это значит, у меня есть только тот фрагмент, который вы опубликовали, чтобы посмотреть. Это полностью объясняет возникшую у вас проблему при блокировке клавиатуры. Начните еще один вопрос о своем исключении GDI +, не забудьте его хорошо документировать. –

+0

, как только я написал комментарий, я понял, что мне нужно было открыть новый вопрос в другом контексте темы, и я это сделал. Спасибо, я отмечаю ваш ответ. – e4rthdog