Universal Hotkey Assignment

  • 15 years ago
    Basically I have a program that is sort of a manager or master program that reads in data from a live excel sheet and intiates certain subroutines by watching hotfolderd and comparing the file's contents to the info in the excel sheet.  Anyway, those details are not that important, the main point is that my program releases control to other programs throughout the different subroutines.  What I would like to do, is assign a hotkey - say CTRL + Q for example -, that would ideally break the subroutine, but even killing the whole program would be acceptable.  My program releases control by using process handles to wait for the other programs to finsih before it continues.  I have to do this because it is important that the programs are run in a particular order and do not overlap.  The reason for this 'esacpe' key, is that if someone drops a file in the hotfolder, or makes an error on the spreadsheet, I would like to have the ability to stop the program instead of having it go through all the motions(some of the longest of subroutines call 30+ programs and can take well over an hour to run - you can see why a halt key would be benefitial).  The way I do process handles is below:

    *Begin Code*

    General Declare

    Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
    Private Declare Function WaitForSingleObject Lib "kernel32.dll" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
    Private Const SYNCHRONIZE = &H100000
    Private Const INFINITE = &HFFFFFFFF

    Private Sub ProcessHandle(Process_ID As String)
           Dim Process_Handle
           On Error GoTo 0
           Process_Handle = OpenProcess(SYNCHRONIZE, 0, Process_ID)
           If Process_Handle <> 0 Then
               Call WaitForSingleObject(Process_Handle, INFINITE)
               Call CloseHandle(Process_Handle)
           End If
    End Sub

    *End Code*

    One of the steps is to grab a database and use a mail software to CASS certify and Pre-sort the address.   For the CASS certification, this is how I am using the handle.

    ProcessHandle (Shell("\\Franklin2003\DP\bcc\mm2010\MAILMAN.EXE -u " & Chr(34) & JobListArray(z).LocalUser & Chr(34) & " -j Cass_Certify" & JobListArray(z).LocalUser & ".mjb", vbNormalFocus))

    Don't pay too much attention to the details in that, basically it works by ProcessHandle(Process) and my programs pauses until the executing program completes its task and closes.  My program then resumes.  I know how to do basic hotkey setups, but those only work if the code is not currently running a subroutine.  For example, I can set CTRL-X to unload my form.  This works while it is stationary, but if it is in a subroutine the hotkey fails.  

    I really don't care about it stopping the currently running process that the handle is waiting on(I can ctrl+alt+del that after my main programs exits).  Just being able to hit a hotkey and then when the currently running program finishes it causes my code to either break the subroutine(as there is usually a long list of other programs to call before the sub is done), or halt and unload itself completely.  I can't figure out a way because as long as the loop is waiting for control to be restored it ignores any keyboard strokes.  So I assume I would need to add something to the process handle subroutine itself that would cause the halt.

    I've done a lot of research, but can't come up with a solution.  If any of you can think of something you would be doing me a great favor.  Thanks for reading my novel

    -Tril
  • 15 years ago

    Just bumping this back up to the front page.  Any off the wall ideas?  I don't mind expiriemnting, or even just a link to some relevant documentation.  I just can't seem to find a good way to break the routine(I'm starting to think of it as a fast moving freight train)..  It's not mission critical, but would really be a nice feature to halt a false or incorrect start of the procedure.


    -Tril

  • 15 years ago
  • 15 years ago
    It seems promising but has some serious bugs I don't understand... and this goes back to why my original way doesnt work.  It seems VB only likes hotkeys if NOTHING is happening.  I ran the example without modification and the hotkey did make a time entry to the text box.  I added this little piece of code:

    Private Sub Command1_Click()
       Dim x As Integer
       Dim y As Integer
       Dim z As Integer
       
       For x = 1 To 10000
           For y = 1 To 10000
               z = 25 * 25
           Next y
       Next x
       MsgBox ("Done Loop")
    End Sub

    So I would click the command button then hit the Alt+F10 hotkey.  Nothing immediatly would happen, but when the loop finished and got to the point of where the msgbox should pop up, everything closed... program, VB, everything.  If I don't hit the hotkey then I will get the message that the loop went through ok.  This is just a simple loop too, I'm not even trying to attempt breaking the handles I have setup in my other program.

    I've tried this little piece of code too...

    Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

       If KeyCode = vbKeyQ And Shift = vbCtrlMask Then
           Unload Me
           End
       End If

    End Sub

    But again, this only works if the form is idle.  Once a procedure has started, this piece of code will not fire.  Is there a way to setup a small piece of code like an interrupt in assembly language?  I started off in assembly and moved to higher forms, so some things that seemed so basic in assembly are a real challenge on higher level programs.  I used to have a watchdog timer that would count up, if more than 5s passed then it reset the chip.  All through out my code I would set the timer to 0.  This way if the code ever locked up, an interrupt would automatically reset the chip and the code.  I just wish I could have something that is always running outside the main loops(like an interrupt)  that could kill the program if I desired.  Oh well... I'll dig around some more.
  • 15 years ago

    In the loop in the Command1_Click chunk of code you posted, try adding:


    Code:

    DoEvents


    to the inner-most loop. This might improve the situation... but, because this effectively pumps all the queued events that are waiting to be processed by your applications message pump, you may suffer a performance penalty as a result.


    If there is a significant performance penalty, try only calling "DoEvents" on every, say, 20th iteration:


    Code:

    If y Mod 20 = 0 Then
     DoEvents
    End If


    Be interested to hear if this makes a difference to the loop.

  • 15 years ago

    It worked!!  At least the small sample program, I have not tried to apply it to my main program yet - that will come soon.  Anyway, the code worked fine with the DoEvents.  I will try adding that to my process handle since technically, my program does not need control while another is running.  It is basically sitting in a loop waiting for a return signal.  I'll let you know how it works out on the main program, here is the code for the example program in case someone else has a similar problem.


    Option Explicit
    ' We got the hotkey.
    Public Sub Hotkey()
       txtTimes.Text = txtTimes.Text & Time & vbCrLf
       txtTimes.SelStart = Len(txtTimes.Text)


       If Me.WindowState = vbMinimized Then Me.WindowState = vbNormal
       Me.SetFocus
    End Sub


    Private Sub Command1_Click()
       Dim x As Integer
       Dim y As Integer
       Dim z As Integer
       
       For x = 1 To 10000
           For y = 1 To 10000
               z = 25 * 25
               If y Mod 20 = 0 Then
                   DoEvents
               End If
           Next y
       Next x
       MsgBox ("Done Loop")
    End Sub


    Private Sub FormLoad()
       ' Register the hotkey.
       If RegisterHotKey(hWnd, HOTKEY
    ID, MODALT, VKF10) = 0 Then
           MsgBox "Error registering hotkey."
           Unload Me
       End If


       ' Subclass the TextBox to watch for
       ' WMHOTKEY messages.
       OldWindowProc = SetWindowLong(hWnd, GWL
    WNDPROC, AddressOf NewWindowProc)
    End Sub


    Private Sub Form_Resize()
       txtTimes.Move 0, 0, ScaleWidth, ScaleHeight
    End Sub

  • 15 years ago

    It works on my main code too!!!  Thanks SO much!  This will save so much time in being able to kill the process instead of waiting for it to run its course on an error.  I did have to add a DoEvents to the loop of the process handle.  I think that was my main problem from the get go.  Since it was stuck in a loop it was ignoring everything but the return signal from the handle.  Even my original keydown code works.  Amazing how one line of code can alter the whole flow of a 30 page piece of code.  

Post a reply

Enter your message below

Sign in or Join us (it's free).

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“The difference between theory and practice is smaller in theory than in practice.”