5 Replies - 13131 Views - Last Post: 01 April 2011 - 01:40 PM Rate Topic: -----

#1 ixoye800  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 20-June 09

Running Function in a Separate Thread

Posted 31 March 2011 - 11:31 PM

I'm having a bit of a problem when trying to run a function in a separate thread, my reason for trying this is because since the application is only run on one thread, the GUI hangs when the function is called.

I know how to make a new thread, it looks something like this:

Dim thread as System.Threading.Thread


Then to call it, i use this code:

thread = New System.Threading.Thread(AddressOf *Function*)
thread.Start()


The function is part of a Global Keyboard Hook (http://jo0ls-dotnet-stuff.blogspot.com/2008/12/vbnet-global-keyboard-hook-to-detect.html) and the purpose is to detect when a certain key is pressed and fire an event.

The function that i want to run in a separate thread is called HookCallBack, and it requires certain variables to be passed to it, here is the full code:

Option Strict On
Option Explicit On

Imports System.Runtime.InteropServices

Public Class Form1

    Private Const WH_KEYBOARD_LL As Integer = 13
    Private Const WM_KEYUP As Integer = &H101
    Private Const WM_SYSKEYUP As Integer = &H105
    Private proc As LowLevelKeyboardProcDelegate = AddressOf HookCallback
    Private hookID As IntPtr

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

    <DllImport("user32")> _
    Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As LowLevelKeyboardProcDelegate, _
        ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function UnhookWindowsHookEx(ByVal hhk As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function CallNextHookEx(ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, _
        ByVal lParam As IntPtr) As IntPtr
    End Function

    <DllImport("kernel32.dll", CharSet:=CharSet.Unicode)> _
    Private Shared Function GetModuleHandle(ByVal lpModuleName As String) As IntPtr
    End Function

    Sub New()
        ' This call is required by the Windows Form Designer.
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call.
        hookID = SetHook(proc)
    End Sub

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles Me.FormClosing
        UnhookWindowsHookEx(hookID)
    End Sub

    Private Function SetHook(ByVal proc As LowLevelKeyboardProcDelegate) As IntPtr
        Using curProcess As Process = Process.GetCurrentProcess()
            Using curModule As ProcessModule = curProcess.MainModule
                Return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0)
            End Using
        End Using
    End Function

    Private Function HookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        ' we check keyup for standard printscreen, and syskeyup incase it is alt+printscreen
        ' we aren't checking keydown, as that fires before the screenshot is taken.
        If nCode >= 0 AndAlso (wParam.ToInt32 = WM_KEYUP OrElse wParam.ToInt32 = WM_SYSKEYUP) Then
            Dim vkCode As Integer = Marshal.ReadInt32(lParam)
            If vkCode = Keys.PrintScreen Then
                Dim data As IDataObject = Clipboard.GetDataObject()
                If data.GetDataPresent(GetType(Bitmap)) Then
                    Me.BackgroundImage = DirectCast(data.GetData(GetType(Bitmap)), Bitmap)
                End If
            End If
        End If
        Return CallNextHookEx(hookID, nCode, wParam, lParam)
    End Function

End Class


In this code, the Print screen Button is pressed and the function HookCallBack is called.
The problem is that the function has variables that need to be passed and returned, and while searching, i found a website that had an answer for this, and it required the function to be put in a class, and then it could be run on a separate thread while still passing all the variables needed. (http://www.devx.com/DevX/10MinuteSolution/20365/0/page/3)

But the code cannot be placed in a class without giving errors and it seems to me like i did something wrong. The code is meant to be used in a form and not a class.

My question is, how would i go about running the HookCallBack Function in a Separate thread? Any help whatsoever is greatly appreciated! :smile2:

Thanks in advance!

Is This A Good Question/Topic? 0
  • +

Replies To: Running Function in a Separate Thread

#2 John-Ellis  Icon User is offline

  • D.I.C Regular

Reputation: 8
  • View blog
  • Posts: 305
  • Joined: 23-March 10

Re: Running Function in a Separate Thread

Posted 01 April 2011 - 04:45 AM

View Postixoye800, on 31 March 2011 - 11:31 PM, said:

I'm having a bit of a problem when trying to run a function in a separate thread, my reason for trying this is because since the application is only run on one thread, the GUI hangs when the function is called.

I know how to make a new thread, it looks something like this:

Dim thread as System.Threading.Thread


Then to call it, i use this code:

thread = New System.Threading.Thread(AddressOf *Function*)
thread.Start()


The function is part of a Global Keyboard Hook (http://jo0ls-dotnet-stuff.blogspot.com/2008/12/vbnet-global-keyboard-hook-to-detect.html) and the purpose is to detect when a certain key is pressed and fire an event.

The function that i want to run in a separate thread is called HookCallBack, and it requires certain variables to be passed to it, here is the full code:

Option Strict On
Option Explicit On

Imports System.Runtime.InteropServices

Public Class Form1

    Private Const WH_KEYBOARD_LL As Integer = 13
    Private Const WM_KEYUP As Integer = &H101
    Private Const WM_SYSKEYUP As Integer = &H105
    Private proc As LowLevelKeyboardProcDelegate = AddressOf HookCallback
    Private hookID As IntPtr

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

    <DllImport("user32")> _
    Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As LowLevelKeyboardProcDelegate, _
        ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function UnhookWindowsHookEx(ByVal hhk As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function CallNextHookEx(ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, _
        ByVal lParam As IntPtr) As IntPtr
    End Function

    <DllImport("kernel32.dll", CharSet:=CharSet.Unicode)> _
    Private Shared Function GetModuleHandle(ByVal lpModuleName As String) As IntPtr
    End Function

    Sub New()
        ' This call is required by the Windows Form Designer.
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call.
        hookID = SetHook(proc)
    End Sub

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles Me.FormClosing
        UnhookWindowsHookEx(hookID)
    End Sub

    Private Function SetHook(ByVal proc As LowLevelKeyboardProcDelegate) As IntPtr
        Using curProcess As Process = Process.GetCurrentProcess()
            Using curModule As ProcessModule = curProcess.MainModule
                Return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0)
            End Using
        End Using
    End Function

    Private Function HookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        ' we check keyup for standard printscreen, and syskeyup incase it is alt+printscreen
        ' we aren't checking keydown, as that fires before the screenshot is taken.
        If nCode >= 0 AndAlso (wParam.ToInt32 = WM_KEYUP OrElse wParam.ToInt32 = WM_SYSKEYUP) Then
            Dim vkCode As Integer = Marshal.ReadInt32(lParam)
            If vkCode = Keys.PrintScreen Then
                Dim data As IDataObject = Clipboard.GetDataObject()
                If data.GetDataPresent(GetType(Bitmap)) Then
                    Me.BackgroundImage = DirectCast(data.GetData(GetType(Bitmap)), Bitmap)
                End If
            End If
        End If
        Return CallNextHookEx(hookID, nCode, wParam, lParam)
    End Function

End Class


In this code, the Print screen Button is pressed and the function HookCallBack is called.
The problem is that the function has variables that need to be passed and returned, and while searching, i found a website that had an answer for this, and it required the function to be put in a class, and then it could be run on a separate thread while still passing all the variables needed. (http://www.devx.com/DevX/10MinuteSolution/20365/0/page/3)

But the code cannot be placed in a class without giving errors and it seems to me like i did something wrong. The code is meant to be used in a form and not a class.

My question is, how would i go about running the HookCallBack Function in a Separate thread? Any help whatsoever is greatly appreciated! :smile2:

Thanks in advance!


Hi

What kind of errors are you getting when you write your function in a class.

Thanks

John
Was This Post Helpful? 0
  • +
  • -

#3 _HAWK_  Icon User is online

  • Master(Of Foo)
  • member icon

Reputation: 1048
  • View blog
  • Posts: 4,075
  • Joined: 02-July 08

Re: Running Function in a Separate Thread

Posted 01 April 2011 - 06:44 AM

The explanation is quite simple. Since you cannot 'pass' the data by way of parameters this offers an alternative. Why can't the APIs be located in a separate class? I put all my API's in it's own class so I can call them from anywhere.
Was This Post Helpful? 0
  • +
  • -

#4 ixoye800  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 20-June 09

Re: Running Function in a Separate Thread

Posted 01 April 2011 - 12:36 PM

@hawkvalley1
Well the problem is, im not much of a professional coder, and i didnt formally learn the language, so API's, Multithreading, and other concepts im just beginning to understand, but i will definitely do more reading about API's.

Even if i wasnt able to put the full code on another class is there a way to run the block of code with the function on a separate thread?

Is it possible to post an example of how i can achieve this or at least something that would point me in the right direction?

Any help is greatly appreciated!



@John
Well if i put this code on a separate class, this line gives me an error:

InitializeComponent()


If i were to successfully place the full code on another class, how would i be able to use it?

Thanks in advance!

This post has been edited by ixoye800: 01 April 2011 - 12:37 PM

Was This Post Helpful? 0
  • +
  • -

#5 _HAWK_  Icon User is online

  • Master(Of Foo)
  • member icon

Reputation: 1048
  • View blog
  • Posts: 4,075
  • Joined: 02-July 08

Re: Running Function in a Separate Thread

Posted 01 April 2011 - 01:24 PM

The InitializeComponent() method should only be called in the Sub New().

Make a class: 'Add New Item' -> select class -> name it. You will also need some class level variables for holding values. Make a new instance of this class and set the variables, now call the sub that uses the variables. Remember the scope of the variables needs to be Friend or Public to be seen by a different class object. Have you tried running those API's without threading - are they slowing down your UI? I would not expect them too.
Was This Post Helpful? 0
  • +
  • -

#6 ixoye800  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 20-June 09

Re: Running Function in a Separate Thread

Posted 01 April 2011 - 01:40 PM

View Posthawkvalley1, on 01 April 2011 - 01:24 PM, said:

The InitializeComponent() method should only be called in the Sub New().

Make a class: 'Add New Item' -> select class -> name it. You will also need some class level variables for holding values. Make a new instance of this class and set the variables, now call the sub that uses the variables. Remember the scope of the variables needs to be Friend or Public to be seen by a different class object. Have you tried running those API's without threading - are they slowing down your UI? I would not expect them too.


Well in reality, im not fully sure what's slowing down the UI, but when the key is pressed, i have set to open a login form, but as soon as it opens, it hangs for about 5 seconds, then the form becomes responsive. I have run the code line by line and the only thing that executes while the login form is opened is the HookCallBack Function, here is the code i modified:

    Private Function HookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        If nCode >= 0 AndAlso (wParam.ToInt32 = WM_KEYUP OrElse wParam.ToInt32 = WM_SYSKEYUP) Then
            Dim vkCode As Integer = Marshal.ReadInt32(lParam)
            If vkCode = Keys.Escape Then
                    frmLogin.ShowDialog()
                End If
            End If
        End If
        Return CallNextHookEx(hookID, nCode, wParam, lParam)
    End Function


And i was thinking that the next thing i could try was to run this on an alternate thread by putting it in a separate class, but that's where im stuck...

I will try to follow your instructions on the class though and see if i get some success.

This post has been edited by ixoye800: 01 April 2011 - 01:44 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1