Browse DevX
Sign up for e-mail newsletters from DevX

Tip of the Day
Language: Visual Basic
Expertise: Beginner
Oct 1, 1996



Building the Right Environment to Support AI, Machine Learning and Deep Learning

Ensuring Single Instance

I have a requirement to only allow a copy of an application to be executed once. If someone tries to execute the app a second time, I want to give a message saying "you're not allowed do this - you only paid for one execution". Do you know a relatively surefire way of doing this? I can think of a few partially acceptable ways but I want a really good method. The app in question runs under Windows 3.x, uses an Access 2.0 database and the standard VB setup program to install itself.

This routine takes advantage of a unique "feature" of Visual Basic applications: the hidden parent. Every VB application has a parent window that remains hidden. The caption on this parent window is the name of the application as provided during the "Make EXE File" process. This is why the name of the application, and not the main window's caption, appears in the Task List when a user presses Ctrl-ESC. Since the parent window is hidden, there has never been a need to change the caption in it. As a result, nearly all VB programs can use this routine. In contrast, the only VB programs that could use the previous routine were those that did not change the caption in their own main window. This limitation may actually have contributed to programmers choosing NOT to use the caption of their main window to impart information, which is unacceptable. There is a class of programs that cannot use this routine: those that set their Application Name in the "Make EXE file" dialog to a zero-length string. Since a large number of windows have a caption of no characters, setting your window title to no text prevents this routine from finding your other instance. Be aware of one limitation in the code: This routine uses App.Previnstance to detect if there is another instance of the program to look for. This is done simply to improve performance, but it has a price. App.Previnstance is set only when the application starts up. Therefore, if you start two instances of the same app, the first one will get a False value, while the second one will get a True value. Therefore, the first instance cannot use this routine to detect the second. If you want to use this routine to allow multiple instances to run, and to have both routines aware of the other's window handle, then take out the use of App.Previnstance completely. Also note that this routine will break down if you want to start three or more instances of your application. If you need to do that, use DDE to communicate between the instances. To declare the routines needed by Get_Other_Instance, place the following lines in the declarations section of the module or form where you put Get_Other_Instance:

Declare Function GetWindowWord% Lib "User" (ByVal hWnd%, ByVal nIndex%)
Declare Function GetWindowText% Lib "User" (ByVal hWnd%, ByVal lpString$, ByVal aint%)
Declare Function GetWindowTextLength% Lib "User" (ByVal hWnd%)
Declare Function GetWindow% Lib "User" (ByVal hWnd%, ByVal wCmd%)
Declare Function SetFocusAPI% Lib "User" Alias "SetFocus" (ByVal hWnd%)

' get window word constants
 Const GWW_HWNDPARENT = (-8)

' get window constants
 Const GW_HWNDNEXT = 2
To use the Get_Other_Instance routine, place the following lines in your Form_Load routine:
Sub Form_Load()
   Dim otherhwnd%
   If Get_Other_Instance(Hwnd, otherhwnd%) then
      MsgBox "Application is already running.  Switching to existing Application"
      SetFocusAPI otherhwnd%
   End If
End Sub
The full text of Get_Other_Instance follows.
' ------------------------------------------------------------------------------------
'  ROUTINE: Get_Other_Instance:BOOL,    Params( inhwnd Inputonly, outhwnd Outputonly)
'  Purpose: to obtain the window handle of another instance of the same program
'  Description: Unlike other examples, this one works even if the main window changes 
'  the caption to reflect the loading of a data file (like MS WORD does).  This works by
'  using a peculiarity of VB.  Every VB program has a parent window above the main window.
'  The caption of the parent window is the text used in the "Make EXE" Dialog for Application
'  name.  The VB programmer cannot easily change this text, and it is hidden to the user,
'  so it is good for this type of operation.
'  INPUT: inhwnd -- the window handle of the calling window
'  OUTPUT: return code is True if a window was found, FALSE otherwise
'          outhwnd -- 0 or set to the hwnd of the parent of the other window
' ------------------------------------------------------------------------------------
Function get_other_instance (ByVal inhwnd As Integer, outhwnd As Integer) As Integer
    Dim parent%, nlen%, ptext$, nexthwnd%, wtext$
    get_other_instance = False
    outhwnd = 0
    If Not app.PrevInstance Then Exit Function

    parent% = GetWindowWord(inhwnd, GWW_HWNDPARENT)
    nlen% = GetWindowTextLength(parent%) + 2
    ptext$ = Space$(nlen%)
    nlen% = GetWindowText(parent%, ptext$, nlen%)
    ptext$ = Left$(ptext$, nlen%)
    nexthwnd% = GetWindow(parent%, GW_HWNDFIRST) ' get the first window in the window list
    Do While nexthwnd% > 0
        nlen% = GetWindowTextLength(nexthwnd%) + 2
        wtext$ = Space$(nlen%)
        nlen% = GetWindowText(nexthwnd%, wtext$, nlen%)
        wtext$ = Left$(wtext$, nlen%)
        If wtext$ = ptext$ And nexthwnd% <> parent% Then
            get_other_instance = True
            outhwnd = nexthwnd%
            Exit Do
        End If
        nexthwnd% = GetWindow(nexthwnd%, GW_HWNDNEXT)

End Function
DevX Pro
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date