Run only one instance of your application: Difference between revisions

From DataFlex Wiki
Jump to navigationJump to search
New page: The question on how to make sure that your application is only started once by your users can be approached in several ways. 1. Using mutexes 2. Using FindWindow WinAPI === Using mutexes...
 
Updated "createmutex succeeded" test to test for NULL not ERROR_INVALID_HANDLE as per Frank Cheng's recommendation see https://support.dataaccess.com/Forums/showthread.php?67791-Limiting-Dataflex-Instances-to-1-per-Laptop&p=368346#post368346
 
(15 intermediate revisions by 5 users not shown)
Line 1: Line 1:
The question on how to make sure that your application is only started once by your users can be approached in several ways.
The question on how to make sure that your application is only started once by your users can be approached in several ways.


1. Using mutexes
# Using mutexes
2. Using FindWindow WinAPI
# Using FindWindow WinAPI
# Using Atoms


=== Using mutexes ===
=== Using mutexes ===
Line 10: Line 11:
Here is the code if you want to go that route."
Here is the code if you want to go that route."


In the SRC file:
In the SRC file within the panel object put this piece of code:
<source lang="dataflex">
Procedure Exit_Application
    integer iVoid
    If (ghMuteX) Move (CloseHandle(ghMutex)) to iVoid
    move 0 to ghMuteX
    Forward Send Exit_Application
End_Procedure
</source>


    Procedure Exit_Application
And in a package that gets hit on startup:
        If (ghMuteX) Move (CloseHandle(ghMutex)) to giTemp
<source lang="dataflex">
        Forward Send Exit_Application
// Constants
    End_Procedure
Define ERROR_INVALID_HANDLE        for 6    //  taken from error.h of VS7
Define ERROR_ALREADY_EXISTS        for 183


//In a package that gets hit on startup:
Handle ghMuteX


Handle ghMuteX
// external functions
#IFNDEF Get_CreateMuteX
    External_Function CreateMuteX "CreateMutexA" Kernel32.dll Integer i1 Integer i2 Integer i3 Returns Integer
#ENDIF
#IFNDEF Get_CloseHandle
  External_Function CloseHandle "CloseHandle" Kernel32.dll Integer i1 Returns Integer
#ENDIF


  #IFNDEF Get_CreateMuteX
// function to create a mutex
  External_Function CreateMuteX "CreateMutexA" Kernel32.dll Integer i1 Integer i2 Integer i3 Returns Integer
Procedure Create_MuteX_Object
  #ENDIF
  Integer iVoid iErr
  String sID
  Move "Unique String For My Application" To sID
  Move (CreateMuteX(0,1,AddressOf(sID))) To ghMuteX
  If (ghMuteX <> 0) Begin
      Move (GetLastError()) To iErr
      If (iErr = ERROR_ALREADY_EXISTS) Begin // program is already
                                              // running
          Move (CloseHandle(ghMuteX)) To iVoid
          Move 0 To ghMuteX
          // kill the application here if you do not want to allow
          // multiple instances
          ABORT
      End
      Else Send None  // program is not already running
  End
  Else Send None // rare error; object could not be created
End_Procedure // Create_MuteX_Object


#IFNDEF Get_CloseHandle
// create the mutex
External_Function CloseHandle "CloseHandle" Kernel32.dll Integer i1 Returns Integer
Send Create_MuteX_Object
#ENDIF
</source>


// CLIENT and SERVER
Dave Robinson says -
Procedure Create_MuteX_Object
A warning: We found CodeJock skinning broke this, though YMMV.
    Integer iVoid iErr
    String sID
    Move "Unique String For My Application" To sID
    Move (CreateMuteX(0,1,AddressOf(sID))) To ghMuteX
    If (ghMuteX <> ERROR_INVALID_HANDLE) Begin
        Move (GetLastError()) To iErr
        If (iErr = ERROR_ALREADY_EXISTS) Begin  // program is already
                                                // running
            Move (CloseHandle(ghMuteX)) To iVoid
            Move 0 To ghMuteX
            // kill the application here if you do not want to allow
            // multiple instances
        End
        Else Send None  // program is not already running
    End
    Else Send None  // rare error; object could not be created
End_Procedure  // Create_MuteX_Object


Send Create_MuteX_Object
=== Using FindWindow WinAPI ===


=== Using FindWindow WinAPI ===
Leslie Brennan says:


Usage in SRC:
Usage in SRC:
 
<source lang="dataflex">
  Use myPanel,pkg
  Use myPanel,pkg
  Object Main is a myPanel
  Object Main is a myPanel
 
</source>


Source myPanel.pkg
Source myPanel.pkg
<source lang="dataflex">
  ////////////////////////////////////////////
  ////////////////////////////////////////////
  //
  //
Line 71: Line 88:


  Class myPanel is a Panel
  Class myPanel is a Panel
    // DoCheckProgramActive
    // Checks if the program already is active.
    // If so, it activates the running application and closes this one.
      Procedure DoCheckProgramActive
        String sTitle
        Handle hWnd
        Integer iVoid


// DoCheckProgramActive
        Register_Object Main
// Checks if the program already is active.
        Get Label of Main to sTitle
// If so, it activates the running application and closes this one.
        Move (FindWindow("",sTitle))  to hWnd
Procedure DoCheckProgramActive
        If (hWnd) Begin
  String sTitle
          Send Stop_Box (sTitle + " Already is Running and Can only be Started Once.") "Error:"
  Handle hWnd
          Move (ShowWindow(hWnd,SW_MAXIMIZE)) to iVoid  // 9 =SW_RESTORE SW_NORMAL
  Integer iVoid
          Move (SetForegroundWindow(hWnd)) to iVoid
          Abort
        End
      End_Procedure // DoCheckProgramActive
 
      // End_Construct_Object
      Procedure End_Construct_Object
        Send DoCheckProgramActive
        Forward Send End_Construct_Object
      End_Procedure // End_Construct_Object
End_class
</source>


  Register_Object Main
The FindWindow technique is also discussed in the book [http://starzen.com/products/books-and-magazines/mastering-visual-dataflex/ Mastering Visual DataFlex] from Starzen.
  Get Label of Main to sTitle


  Move (FindWindow("",sTitle))  to hWnd
Dave Robinson says:
  If (hWnd) Begin
The FindWindow method depends on the Title in the program taskbar being known and consistent.
      Send Stop_Box (sTitle + " Already is Running and Can only be Started Once.") "Error:"
      Move (ShowWindow(hWnd,SW_MAXIMIZE)) to iVoid  // 9 =SW_RESTORE SW_NORMAL
      Move (SetForegroundWindow(hWnd)) to iVoid
      Abort
  End
End_Procedure // DoCheckProgramActive


// End_Construct_Object
Procedure End_Construct_Object
    Send DoCheckProgramActive
    Forward Send End_Construct_Object
End_Procedure // End_Construct_Object


End_class
[[Category: Tutorials]]

Latest revision as of 14:30, 27 September 2021

The question on how to make sure that your application is only started once by your users can be approached in several ways.

  1. Using mutexes
  2. Using FindWindow WinAPI
  3. Using Atoms

Using mutexes

Dalton Pulsipher says: "We use a MuteX object to do this. Just attach one to your program and on startup check if it already exists on the system. Here is the code if you want to go that route."

In the SRC file within the panel object put this piece of code:

Procedure Exit_Application
    integer iVoid
    If (ghMuteX) Move (CloseHandle(ghMutex)) to iVoid
    move 0 to ghMuteX
    Forward Send Exit_Application
End_Procedure

And in a package that gets hit on startup:

// Constants
Define ERROR_INVALID_HANDLE        for 6    //  taken from error.h of VS7
Define ERROR_ALREADY_EXISTS        for 183

Handle ghMuteX

// external functions
#IFNDEF Get_CreateMuteX
    External_Function CreateMuteX "CreateMutexA" Kernel32.dll Integer i1 Integer i2 Integer i3 Returns Integer
#ENDIF
#IFNDEF Get_CloseHandle
   External_Function CloseHandle "CloseHandle" Kernel32.dll Integer i1 Returns Integer
#ENDIF

// function to create a mutex
Procedure Create_MuteX_Object
   Integer iVoid iErr
   String sID
   Move "Unique String For My Application" To sID
   Move (CreateMuteX(0,1,AddressOf(sID))) To ghMuteX
   If (ghMuteX <> 0) Begin
       Move (GetLastError()) To iErr
       If (iErr = ERROR_ALREADY_EXISTS) Begin  // program is already 
                                               // running
           Move (CloseHandle(ghMuteX)) To iVoid
           Move 0 To ghMuteX
           // kill the application here if you do not want to allow 
           // multiple instances
           ABORT
       End
       Else Send None  // program is not already running
   End
   Else Send None  // rare error; object could not be created
End_Procedure  // Create_MuteX_Object

// create the mutex
Send Create_MuteX_Object

Dave Robinson says - A warning: We found CodeJock skinning broke this, though YMMV.

Using FindWindow WinAPI

Leslie Brennan says:

Usage in SRC:

 Use myPanel,pkg
 Object Main is a myPanel

Source myPanel.pkg

 ////////////////////////////////////////////
 //
 // 05/24/2007 
 // Panel Class from Pieter van Dieren to check
 // to make sure program is only run one time.
 //
 /////////////////////////////////////////////

 Use dfPanel.pkg

 Class myPanel is a Panel
    // DoCheckProgramActive
    // Checks if the program already is active.
    // If so, it activates the running application and closes this one.
      Procedure DoCheckProgramActive
        String sTitle
        Handle hWnd
        Integer iVoid

        Register_Object Main
        Get Label of Main to sTitle
        Move (FindWindow("",sTitle))  to hWnd
        If (hWnd) Begin
          Send Stop_Box (sTitle + " Already is Running and Can only be Started Once.") "Error:"
          Move (ShowWindow(hWnd,SW_MAXIMIZE)) to iVoid  // 9 =SW_RESTORE SW_NORMAL
          Move (SetForegroundWindow(hWnd)) to iVoid
          Abort
        End
      End_Procedure // DoCheckProgramActive

      // End_Construct_Object
      Procedure End_Construct_Object
        Send DoCheckProgramActive
        Forward Send End_Construct_Object
      End_Procedure // End_Construct_Object
 End_class

The FindWindow technique is also discussed in the book Mastering Visual DataFlex from Starzen.

Dave Robinson says: The FindWindow method depends on the Title in the program taskbar being known and consistent.