2012-04-29 53 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應用程序的一般要求,佔用主UI線程以及其他任務使得用戶界面緊張。它停止響應輸入並停止繪畫。幾秒鐘後,Windows窗口管理器進入,並用'ghost窗口'替換主窗口,在標題欄中顯示「Not Responding」。您的鼻子被磨擦得更加困難,因爲此時鍵盤輸入也停止了,Window無法調用鉤子回調。

您需要在另一個線程上執行長時間運行的任務,以便UI線程可以保持響應。或者在您正在討論的特定情況下,請改用UploadFileAsync()。

+0

我去了,從這裏得到了示例源代碼:[MSDN示例](http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx)...這裏的問題是我有一個計時器組件上傳。在上傳應用程序之前,捕獲屏幕部分並保存爲jpg。現在異步的問題是,有時候有時候會出現gdi + excpetion ... – e4rthdog 2012-04-29 16:44:59

+0

我不知道這是什麼意思,我只有你發佈的代碼片段。這完全解釋了你最初在鍵盤鎖定時遇到的問題。開始另一個關於你的GDI +異常的問題,一定要記錄下來。 – 2012-04-29 16:49:40

+0

只要我寫評論我明白,我不得不在另一個主題上下文中打開一個新的問題,我做了。謝謝,我正在標記你的答案。 – e4rthdog 2012-04-29 16:58:12