3

Suppose a user minimize my visual basic application to the taskbar notification icon. Now I want when user open a new instance, the old one should restore.

  • 5
    [What have you tried?](http://mattgemmell.com/2008/12/08/what-have-you-tried/) – Polynomial Jul 26 '12 at 12:35
  • I have not tried anything, but thought of sending message to old instance by creating a value in registry, but I am looking for some neat way that doesn't require timer.... –  Jul 26 '12 at 12:37
  • 3
    Why not just have the new app check for an existing instance (e.g. with a [mutex](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682411.aspx)) and, if it exists, use [`FindWindow`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499.aspx) and [`SetWindowPos`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633545.aspx) to find the hWnd and show/restore the window? – Polynomial Jul 26 '12 at 12:39
  • It does not work, I have used form1.hide to hide app when in taskbar –  Jul 26 '12 at 12:45
  • 2
    How do you know it doesn't work, you just said you have not tried anything? – LittleBobbyTables - Au Revoir Jul 26 '12 at 12:50
  • 1
    Why are you hiding it on a minimise? That's probably why they keep starting a new copy... – Deanna Jul 26 '12 at 14:27

2 Answers2

12

Generally, the strategy used to create a single-instance application is to add some code to the application initialization that determines whether an instance is already running. If one is, it gets a handle to its main window, passes the focus to it, and silently dies. If one is not, it continues to run and completes the rest of the initialization sequence as usual.

You'll find lots of old VB 6 articles that accomplished this by iterating through all of the top-level windows, looking for one whose caption matches the one you expect. But this is a pretty fragile solution, it doesn't take very much to throw it off.

Same deal with the App.PrevInstance property. This is very simple to use, but also very simple in its implementation. It works based on the name of the executable and looks for a running process whose name is a match. However, this is easily defeated if a user creates and renames a copy of the executable. If this is acceptable for you, you could implement this very easily by querying the App.PrevInstance property. Otherwise, you'll need to use a more robust solution.

One such possibility is to create and register a named mutex when the first instance of your application is starting up. Then, when subsequent instances try to register that same mutex, they will fail, indicating that an instance is already running. You can find instructions on using mutexes in VB 6 in the answers to this question.

A couple of important caveats to using mutexes:

  • You need to make sure that you call the ReleaseMutex and CloseHandle functions when your application is closed in order to release ownership of and destroy the mutex that you created.

  • When you are running your program in the VB 6 IDE (e.g., to debug it) and it registers a mutex, the mutex belongs to the IDE and won't be released until you close the IDE and restart it. To prevent this, you can suppress the creation of the mutex when running inside of the IDE/debugger using conditional compilation. If you take this approach, make sure to test your program outside of the debugger to be sure that the mutex-related functionality is working as expected! You should never ship something to customers that you haven't thoroughly tested.

You can find all of the VB 6 declarations for these Windows API functions by using the API Viewer program that comes bundled with your VB 6 installation.

More information about handling multiple instances of a VB 6 application is available here on Karl Peterson's site. There's also a complete example implementation in this article on VB Accelerator—focus specifically at step 2, you don't need the rest of the code.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Great answer. I was writing one, but yours covered everything I was going to say and more. – Polynomial Jul 26 '12 at 12:49
  • +1. I was writing something similar, but you apparently can find links faster than I can. :-) – Ken White Jul 26 '12 at 12:50
  • Sorry, i have understand all this and also checked http://support.microsoft.com/kb/185730 but my old instance has used me.hide code and display in taskbar, but what i want is exexution me.show code when a new instance is created. –  Jul 26 '12 at 12:50
  • @Varun: Yes. The idea is to detect if a previous instance is running, and if it is, to set focus to that instance and bring it to the foreground. However you bring the application to the foreground when someone double-clicks on your notification area icon is the same way that you'd bring a previous instance to the foreground before ending the duplicate instance. – Cody Gray - on strike Jul 26 '12 at 12:54
  • +1. Great answer! But you don't need to do anything special when your program closes. Windows will automatically release the mutex and close the handle when the process terminates. – MarkJ Jul 26 '12 at 18:49
  • @MarkJ Thanks. That's probably true, but I like to explicitly clean up after myself. If I just tear down everything that I create, it saves me from having to remember which things Windows will clean up and which things will leak. Windows cleaning up after me is mostly useful after a hard crash when finalization code never has a chance to run. – Cody Gray - on strike Jul 26 '12 at 23:18
  • I explicitly clear up after myself *almost* always. This is one case where I don't. Windows [guarantees](http://msdn.microsoft.com/en-us/library/windows/desktop/ms684266.aspx) to tidy up the mutex when the thread terminates. In this case, that's exactly the behaviour required. So why code it explicitly? We've been using mutexes like this for years in apps with hundreds of users and we've never released a mutex explicitly! No bug reports yet :) – MarkJ Jul 28 '12 at 09:07
7

You can often do this fairly simply using DDE in a degenerate way:

Form1.frm

Option Explicit
'This is Form1.  To use as DDE source at design time we set:
'   Form1.LinkMode = 1 (Source, i.e. vbLinkSource).
'   Form1.LinkTopic = "Form1" (default).
'
'Note we use (hidden) Label1 on this Form as a DDE destination.

Private PrevState As Integer

Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer)
    'Got a "command" so restore Form1 and accept the command.
    WindowState = PrevState
    Caption = "I am awake!"
    Cancel = False
End Sub

Private Sub Form_Load()
    PrevState = WindowState
End Sub

Private Sub Form_Resize()
    If WindowState <> vbMinimized Then PrevState = WindowState
End Sub

Module1.bas

Option Explicit

Private Sub Main()
    Load Form1
    'After Form1 is loaded (hidden), try DDE link to possible prior copy.
    With Form1.Label1
        .LinkTopic = App.EXEName & "|Form1"
        On Error Resume Next
        .LinkMode = vbLinkManual
        If Err.Number = 0 Then
            On Error GoTo 0
            'Link succeeded.  Wake up prior copy via pushback to
            'the DDE source, then unload Form1 and terminate.
            .LinkExecute "Wake up!"
            Unload Form1
        Else
            On Error GoTo 0
            'Link failed, so we're 1st.  Show Form1.
            Form1.Show vbModal
        End If
    End With
End Sub
Bob77
  • 13,167
  • 1
  • 29
  • 37
  • I like this +1. "Degenerate" it may be, but no more so than having to provide some external indicator to a new instance about whether to restore `Normal` or `Maximized.` I think it would also be pretty easy to adapt if the app uses more than one top-level window. It certainly seems a neater solution than the API methods I've used in the past. – Antagony Jul 26 '12 at 14:06
  • Perhaps a better word might be vestigial, minimal, trivial, or even *repurposed*. "Degenerate" has too many negative connotations in common speech. – Bob77 Jul 26 '12 at 14:10
  • @Rob To be honest I don't actually know what the term "degenerate" means in programming. I've seen it used occasionally and kind of assumed it meant something like "incorrect usage", but no doubt I'm miles off target with that. :-) – Antagony Jul 26 '12 at 15:02
  • Well it has certain literal meanings in engineering and mathmatics completely isolated from the social connotations of lay speech. For example in geometry a point is a degenerate circle, a circle is a degenerate ellipse, etc. – Bob77 Jul 26 '12 at 15:18