Results 1 to 16 of 16

Thread: Find previous instance (not App.PrevInstance)

  1. #1

    Thread Starter
    Hyperactive Member brenaaro's Avatar
    Join Date
    Sep 2001
    Location
    Montreal, Canada
    Posts
    391

    Find previous instance (not App.PrevInstance)

    How can my application know if there are any previous instances of this application running, and know when they have terminated.

    I want my program to be able to sit and wait until any previous instance of itself has terminated, before displaying a form. So App.PrevInstance is no good because it does not refresh.

    The title of the windows in this application will not be constant, the only thing I will know for sure is the path to, and name of the .exe file.

    So basically;

    Are there some API's I can use to determine if windows is running any instances of an executable, that's not the current instance..

    Thanks
    Last edited by brenaaro; Sep 19th, 2002 at 02:01 PM.
    And I, for one, welcome our new insect overlords. I'd like to remind them as a trusted TV personality, I can be helpful in rounding up others to toil in their underground sugar caves.

  2. #2
    Hyperactive Member
    Join Date
    Feb 2001
    Posts
    421
    App.PrevInstance doesn't work even if it's in a loop?
    [vbcode]
    ' comment
    Rem remark
    [/vbcode]

  3. #3

    Thread Starter
    Hyperactive Member brenaaro's Avatar
    Join Date
    Sep 2001
    Location
    Montreal, Canada
    Posts
    391
    No, it won't tell you if the previous instance has been closed after the initial check.
    And I, for one, welcome our new insect overlords. I'd like to remind them as a trusted TV personality, I can be helpful in rounding up others to toil in their underground sugar caves.

  4. #4
    Software Eng. Megatron's Avatar
    Join Date
    Mar 1999
    Location
    Canada
    Posts
    11,286
    You could probably get by with FindWindow.

  5. #5

    Thread Starter
    Hyperactive Member brenaaro's Avatar
    Join Date
    Sep 2001
    Location
    Montreal, Canada
    Posts
    391
    If it ends up that the form caption will always be the same then I will use that. It looks like the caption may be a variable though, depending on an argument passed to the executable.

    I'll probably end up keeping a running tally of process IDs in a file and cycle through them, checking which ones are open and such. Each instance would add/remove it's own process ID as it opens/closes
    And I, for one, welcome our new insect overlords. I'd like to remind them as a trusted TV personality, I can be helpful in rounding up others to toil in their underground sugar caves.

  6. #6
    Frenzied Member
    Join Date
    Jul 2002
    Posts
    1,370
    Use your own Mutex (App.PrevInstance is a mutex) - a mutual exclusion semaphore - maintained in kernel.

    Name them like myapp1, myapp2... myappn.
    Maintain them and check them, this limits your app to 10 instances.

    Code:
    Private Const ERROR_ALREADY_EXISTS = 183&
    Private Const LIMIT = 10 ' we want no more than 10 instances of myapp
    Dim myMutex as long
    Private Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Any, ByVal bInitialOwner As Long, ByVal lpName As String) As Long
    Private Declare Function ReleaseMutex Lib "kernel32" (ByVal hMutex As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    
    Sub  NewApp() as long  ' run me when starting
        Dim tmp as string, working as String
        Dim x
        tmp= App.Title
        x=1
        myMutex=0
        Do while myMutex = 0
           myMutex = TryMutex(tmp & x)      
           x = x + 1
           if x > LIMIT then
               msgBox "Too many instances of this app. Cannot Continue",vbOkOnly
               end
           end if
        Loop
        
    End Sub
    
    Function CanIShowForm() as Boolean
        dim instances as long
        dim tmp,x
        instances = 0
        tmp=App.Title
        for x=1 to LIMIT
             instances = instacnes + TryMutex(tmp & x)
        next
        if instances = 1 then ' this is the only one out there
               CanIShowForms = True
        else
               CanIShowForms = False
        End if
    End Function
    
    Function TryMutex(name as String) as long
        Dim hMutex as long
        hMutex = CreateMutex(ByVal 0&, 1, name)  
        If (Err.LastDllError = ERROR_ALREADY_EXISTS) Then
            ReleaseMutex hMutex
            CloseHandle hMutex
            TryMutex = 0
        Else
            TryMutex=hMutex
        End If
    End Function
    
    Sub CLoseApp()
        CloseHandle myMutex
        Set Form1=Nothing
        End
    End Sub

  7. #7
    Frenzied Member
    Join Date
    Jul 2002
    Posts
    1,370
    Friendly warning

    BE SURE! you close the mutex when you exit, even if it's an error.
    If you are in development be sure you let the ide execute the CloseApp sub.

    If you don't you cannot clear mutexes - they will build up and you will have to reboot.

  8. #8

    Thread Starter
    Hyperactive Member brenaaro's Avatar
    Join Date
    Sep 2001
    Location
    Montreal, Canada
    Posts
    391
    Wow, thanks Jim! This is all new stuff to me.

    I'll give it a try at work tomorow.
    And I, for one, welcome our new insect overlords. I'd like to remind them as a trusted TV personality, I can be helpful in rounding up others to toil in their underground sugar caves.

  9. #9

    Thread Starter
    Hyperactive Member brenaaro's Avatar
    Join Date
    Sep 2001
    Location
    Montreal, Canada
    Posts
    391

    Question question

    Just a quick question, what is CanIShowForm() supposed to do? When I ran through it, it created all remaining Mutex's (up to LIMIT).

    Granted I could close them all by running through it again, but I was just curious. It looks like it's supposed to return a count of open Mutexes, but it just adds up the handles to those Mutes that it opens.

    If I wanted to count the instances of Mutes, would I do something like this?
    VB Code:
    1. Function CanIShowForm() as Boolean
    2.     Dim instances as long
    3.     Dim tmp,x
    4.     instances = 0
    5.     tmp=App.Title
    6.     For x=1 to LIMIT
    7.          instances = instances + CountMutex(tmp & x)
    8.     Next
    9.     ' = 0 instead of = 1?
    10.     If instances = 0 Then ' this is the only one out there
    11.            CanIShowForms = True
    12.     Else
    13.            CanIShowForms = False
    14.     End if
    15. End Function
    16.  
    17. Function CountMutex(name as String) as long
    18.     Dim hMutex as long
    19.     hMutex = CreateMutex(ByVal 0&, 1, name)  
    20.  
    21.                                    'Don't want to close my own Mutex, correct?
    22.     If (Err.LastDllError = ERROR_ALREADY_EXISTS) And hMutex <> myMutex Then
    23.         ReleaseMutex hMutex
    24.         CloseHandle hMutex
    25.         CountMutex = 1
    26.     Else
    27.         'Also dont want to open any new ones?
    28.         ReleaseMutex hMutex
    29.         CloseHandle hMutex
    30.     End If
    31. End Function

    One more thing, the LIMIT of 10, was that an arbitrary number or is does it have significance? Thanks
    And I, for one, welcome our new insect overlords. I'd like to remind them as a trusted TV personality, I can be helpful in rounding up others to toil in their underground sugar caves.

  10. #10
    old fart Frans C's Avatar
    Join Date
    Oct 1999
    Location
    the Netherlands
    Posts
    2,926
    I think a better solution would be to create a semaphore, with an initial count of 1, and a maximumcount of 1.

    Call CreateSemaphore when your app starts, followed by a WaitForSingleObject. If your instance is the first, it will return immediately, otherwise it will wait untill the previous instance called ReleaseSemaphore.

    When your app gets closed, call ReleaseSemaphore, followed by a CloseHandle.

    This way, you don't have to poll untill you can show your form, the WaitForSingleObject simply returns as soon as it is your turn. Another advantage is that the instances will be running when it is their turn. The second instance will display the form, as soon as the first instance is ready, and the third instance as soon as the second instance is ready. semaphores automatically use the FIFO principle (First In First Out)


    I will see if I can write a sample when I get home. I can't spent too much time right now, because i am at work.

  11. #11

    Thread Starter
    Hyperactive Member brenaaro's Avatar
    Join Date
    Sep 2001
    Location
    Montreal, Canada
    Posts
    391

    Wink Mutex, Semphores and more! Oh my!

    Mutex, Semaphore..all one big heap of mumbo-jumbo to me at this point in time ;-)

    I'll try seeing what MSDN has to say about Semaphores but if you can come up with an example that would be great.
    And I, for one, welcome our new insect overlords. I'd like to remind them as a trusted TV personality, I can be helpful in rounding up others to toil in their underground sugar caves.

  12. #12
    Frenzied Member
    Join Date
    Jul 2002
    Posts
    1,370
    Frans C suggestion is better in this case. I just went the way
    App.Previnstance goes.

    Sempahores work the same way mutexes do - you call create, get the handle, increment or decrement, then closehandle - but they are a flag that gets set. Think of them as an event flag.

  13. #13
    old fart Frans C's Avatar
    Join Date
    Oct 1999
    Location
    the Netherlands
    Posts
    2,926
    OK, here it is.
    Add a standard module to a project, and add this code.
    Set your startup to Sub main.

    VB Code:
    1. Option Explicit
    2. Private Declare Function CreateSemaphore Lib "kernel32" Alias "CreateSemaphoreA" (ByVal lpSemaphoreAttributes As Long, ByVal lInitialCount As Long, ByVal lMaximumCount As Long, ByVal lpName As String) As Long
    3. Private Declare Function ReleaseSemaphore Lib "kernel32" (ByVal hSemaphore As Long, ByVal lReleaseCount As Long, lpPreviousCount As Long) As Long
    4. Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    5. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    6.  
    7. Private Const INFINITE = &HFFFF
    8. Private lngSemaphore As Long
    9. Private Const MaxInst As Long = 1 ' change this to 2, if you want a maximum of 2 instances to display the form at the same time
    10.  
    11.  
    12. Sub Main()
    13. Dim lngRet As Long
    14.     'A semaphore counts down to 0, because we start at 1 only one instance will show the form at the same time
    15.     ' create the semaphore. If a previous instance exists, this function returns a handle to the existing one.
    16.     lngSemaphore = CreateSemaphore(0&, MaxInst, MaxInst, "MyCoolProgram")
    17.     ' We wait untill we can start our form. If this is the first instance, we don't wait long.
    18.     ' this call will decrease the counter. If the counter is at 0, it waits until another instance increases it
    19.     lngRet = WaitForSingleObject(lngSemaphore, INFINITE)
    20.     ' Ok, now show the form
    21.     Form1.Show
    22. End Sub
    23.  
    24.  
    25. Public Sub Cleanup()
    26. Dim lngRet As Long
    27.     ' we increase the counter with 1, if other instances are waiting, the first one can stop waiting
    28.     lngRet = ReleaseSemaphore(lngSemaphore, 1&, 0&)
    29.     ' close the handle
    30.     lngRet = CloseHandle(lngSemaphore)
    31. End Sub

    Add this code to form1

    VB Code:
    1. Private Sub Form_Unload(Cancel As Integer)
    2.     Call Cleanup
    3. End Sub

  14. #14

    Thread Starter
    Hyperactive Member brenaaro's Avatar
    Join Date
    Sep 2001
    Location
    Montreal, Canada
    Posts
    391
    Ok, looks simple enough.

    Just a quick question about WaitForSingleObject.

    Say I wanted the current instance to only wait 5 seconds for it's turn before giving up and closing.

    I would pass 5000& to dwMilliseconds but does that mean that if it does not get it's turn after 5 seconds, it returns a timeout value (and what is the value for WAIT_TIMEOUT btw..)?
    And I, for one, welcome our new insect overlords. I'd like to remind them as a trusted TV personality, I can be helpful in rounding up others to toil in their underground sugar caves.

  15. #15
    old fart Frans C's Avatar
    Join Date
    Oct 1999
    Location
    the Netherlands
    Posts
    2,926
    Ok, to wait only 5 seconds, pass 5000& as dwmilliseconds, like you already mentioned. If it times out, the retgurn value (lngRet )will be equal to WAIT_TIMEOUT (&H102).

    If you want to exit after the timeout, you should not call ReleaseSemaphore (this would increase the counter, while you didn't decrease it), but you should close the handle.

    So here is the modified code:

    In a module:
    VB Code:
    1. Option Explicit
    2. Private Declare Function CreateSemaphore Lib "kernel32" Alias "CreateSemaphoreA" (ByVal lpSemaphoreAttributes As Long, ByVal lInitialCount As Long, ByVal lMaximumCount As Long, ByVal lpName As String) As Long
    3. Private Declare Function ReleaseSemaphore Lib "kernel32" (ByVal hSemaphore As Long, ByVal lReleaseCount As Long, lpPreviousCount As Long) As Long
    4. Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    5. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    6.  
    7. Private Const INFINITE = &HFFFF
    8. Private Const WAIT_TIMEOUT = &H102
    9. Private lngSemaphore As Long
    10. Private Const MaxInst As Long = 1 ' change this to 2, if you want a maximum of 2 instances to display the form at the same time
    11.  
    12.  
    13. Sub Main()
    14. Dim lngRet As Long
    15.     'A semaphore counts down to 0, because we start at 1 only one instance will show the form at the same time
    16.     ' create the semaphore. If a previous instance exists, this function returns a handle to the existing one.
    17.     lngSemaphore = CreateSemaphore(0&, MaxInst, MaxInst, "MyCoolProgram")
    18.     ' We wait untill we can start our form. If this is the first instance, we don't wait long.
    19.     ' this call will decrease the counter. If the counter is at 0, it waits until another instance increases it
    20.     lngRet = WaitForSingleObject(lngSemaphore, 5000&)
    21.     If lngRet <> WAIT_TIMEOUT Then
    22.         ' Ok, now show the form
    23.         Form1.Show
    24.     Else
    25.         ' close the handle
    26.         lngRet = CloseHandle(lngSemaphore)
    27.     End If
    28. End Sub
    29.  
    30.  
    31. Public Sub Cleanup()
    32. Dim lngRet As Long
    33.     ' we increase the counter with 1, if other instances are waiting, the first one can stop waiting
    34.     lngRet = ReleaseSemaphore(lngSemaphore, 1&, 0&)
    35.     ' close the handle
    36.     lngRet = CloseHandle(lngSemaphore)
    37. End Sub

    The form code stays the same.

  16. #16

    Thread Starter
    Hyperactive Member brenaaro's Avatar
    Join Date
    Sep 2001
    Location
    Montreal, Canada
    Posts
    391

    Perfect

    Absolutely perfect.

    I tried it all out and it works like a charm!

    Thanks a bunch folks!
    And I, for one, welcome our new insect overlords. I'd like to remind them as a trusted TV personality, I can be helpful in rounding up others to toil in their underground sugar caves.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width