Run only one instance of your application: Difference between revisions
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. | ||
# Using mutexes | |||
# 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> | |||
And in a package that gets hit on startup: | |||
<source lang="dataflex"> | |||
// 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 | |||
</source> | |||
Dave Robinson says - | |||
A warning: We found CodeJock skinning broke this, though YMMV. | |||
=== 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 | |||
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 | |||
</source> | |||
The FindWindow technique is also discussed in the book [http://starzen.com/products/books-and-magazines/mastering-visual-dataflex/ Mastering Visual DataFlex] from Starzen. | |||
Dave Robinson says: | |||
The FindWindow method depends on the Title in the program taskbar being known and consistent. | |||
[[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.
- Using mutexes
- Using FindWindow WinAPI
- 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.