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_HWNDFIRST = 0 Const GW_HWNDNEXT = 2To 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 End If End SubThe 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) LoopEnd Function