View previous topic :: View next topic |
Author |
Message |
wahorger
Joined: 13 Oct 2014 Posts: 1226 Location: Morrison, CO, USA
|
Posted: Thu Dec 10, 2020 6:24 pm Post subject: Preventing multiple instances of a program from running |
|
|
How does one make sure that multiple instances of a program are not running?
There are some times where it would be useful to limit a user's ability to wrap themselves around a proverbial axle when programs crash due to file conflicts.
I've tried searching the HELP files and this Forum, but either my queries are too ambiguous or there's nothing there on this subject.
Bill |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8019 Location: Salford, UK
|
Posted: Thu Dec 10, 2020 7:41 pm Post subject: |
|
|
One way is to call the Microsoft function FindWindow. I can get details tomorrow if this is of interest. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1226 Location: Morrison, CO, USA
|
Posted: Thu Dec 10, 2020 9:07 pm Post subject: |
|
|
It is of interest to me. Sometimes my users don't remember that they have an instance running, then it will fail to open a file, and I get a frantic call (or e-mail). Better to let them know "we don't really support this".
Thanks,
Bill |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8019 Location: Salford, UK
|
Posted: Fri Dec 11, 2020 9:09 am Post subject: |
|
|
In this sample one or other of the arguments for FindWindow can be set to CORE4(0) or CORE8(0).
Code: | module mymod
use mswin
contains
logical function start()
integer(7) hwnd,h1
logical L
start = .true.
hwnd = FindWindow("SalfordDialog","My Editor")
if(hwnd /= 0)then
!Not sure how many of these you need...
L=SetForegroundWindow(hwnd)
L=BringWindowToTop(hwnd)
h1=SetActiveWindow(hwnd)
h1=SetFocus(hwnd)
start = .false.
endif
end function start
end module mymod
winapp
program main
use mymod
integer iw
character*1025 buffer
if(start())then
buffer = " "
iw = winio@("%ca[My Editor]&")
iw = winio@("%pv%30.10re", buffer)
endif
end program main |
|
|
Back to top |
|
|
Kenneth_Smith
Joined: 18 May 2012 Posts: 717 Location: Hamilton, Lanarkshire, Scotland.
|
Posted: Fri Dec 11, 2020 3:34 pm Post subject: |
|
|
My "clunky" solution is to use the presence of a file created by the first executable to block the second.
Code: | winapp
module test_mod
implicit none
integer :: block_unit=90
contains
! Checks to see if file exists, if it does STOP, otherwise create file.
integer function init()
integer ERROR_CODE
if (FEXISTS@('status.txt', ERROR_CODE)) then
STOP "Already running"
else
open (unit=block_unit,file='status.txt',status='new')
end if
init = 1
end function init
! Deletes file at end of this run in preparation for next run
integer function deinit()
integer ERROR_CODE
if (FEXISTS@('status.txt', ERROR_CODE)) close (unit=block_unit,status = 'delete')
deinit=1
end function deinit
integer function main_code()
integer i
i = init()
! Main program calls go here, eg:
do i = 1, 100000
print*, i
end do
i = deinit()
main_code = 1
end function main_code
end module test_mod
program main
use test_mod
i = main_code()
end program main |
Last edited by Kenneth_Smith on Fri Dec 11, 2020 6:42 pm; edited 1 time in total |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1226 Location: Morrison, CO, USA
|
Posted: Fri Dec 11, 2020 3:46 pm Post subject: |
|
|
I tried setting the second parameter to core4(0) to get ANY class named "SalfordDialog". This caused an Access Violation in MAKE_CSTRING# (Checkmate Win32) so I wrote a smaller test program (error below).
Quote: | Runtime error from program:z:\fpstackfault\release\win32\forumtesting.exe
Access Violation
The instruction at address 1016ebd8 attempted to read from location 00000003
1016ebb0 MAKE_CSTRING# [+0028]
00401000 MAIN [+0059]
eax=00404320 ebx=0000484f ecx=00000004
edx=000000fe esi=0360fc64 edi=00000003
ebp=0360fc50 esp=0360fc2c IOPL=2
ds=002b es=002b fs=0053
gs=002b cs=0023 ss=002b
flgs=00010606 [NC EP NZ SN UP NV]
1016ebd8 rep
1016ebd9 scasb
1016ebda cld
|
I created a new function definition as:
Code: | stdcall findwindow_new 'FindWindowA' (string,ref):integer(7) |
This does not crash.
It (usually) finds another application with the class name "SalfordDialog", but not always. Still trying to figure that one out.
Bottom line is: This can work! |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8019 Location: Salford, UK
|
Posted: Fri Dec 11, 2020 5:07 pm Post subject: |
|
|
Bill
If you don't match the caption then FindWindow will report the first ClearWin+ executable that if finds. They all have the same class name.
If you can identify your application from part of the caption rather than the whole then you could call EnumWindows and use it to read and test all of the captions in turn. This is a bit more tricky and is probably best done in a C function. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1226 Location: Morrison, CO, USA
|
Posted: Sat Dec 12, 2020 12:43 am Post subject: |
|
|
When I ran the test case (looking for SalfordDialog before my local window was created), I got mixed results.
So, I performed a getclassname() inside of the %sc call for the window that is created in the alternate path, while using the %hw to get the window handle in the "normal path".
In the normal case, it returned the value expected. In the other, it returns:
Quote: | SalfordDialog_win_icon0 |
I do use %mi and use the string 'win_icon' to specify the resource.
Is it possible that since I make the window [invisible] initially that the class name is different?
Bill |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8019 Location: Salford, UK
|
Posted: Sat Dec 12, 2020 9:35 am Post subject: |
|
|
Bill
Yes you have discovered something new to me.
ClearWin+ does register a class for a %mi icon. At the moment I don't know why it does that or if it is necessary. |
|
Back to top |
|
|
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8019 Location: Salford, UK
|
Posted: Sat Dec 12, 2020 1:05 pm Post subject: |
|
|
Bill
I think that you could call FindWindow twice. Once using SalfordDialog and once using SalfordDialog_win_icon0. You would also use your special interface for FindWindow (assuming that you don't know the precise caption).
If your application has only one %mi then SalfordDialog_win_icon0 will be unique to the application. If you have two %mi's then the first will have the class name SalfordDialog_win_icon0 and the second SalfordDialog_win_icon1 etc.
I am guessing that you will only get SalfordDialog_win_icon0 when the application is minimised but trial and error will tell. |
|
Back to top |
|
|
jalih
Joined: 30 Jul 2012 Posts: 196
|
Posted: Sat Dec 12, 2020 3:37 pm Post subject: |
|
|
I think that instead of using FindWindow(), you should use named mutex to prevent running multiple instances of a program.
I once used following with MiniBasic code (Should translate to C++ easily):
Code: |
func GUIDstr(), wstring
GUID pGUID
wstring str
if CoCreateGuid(pGUID) = 0
StringFromGUID2(pGUID,str,39)
endif
return str
endf
func app_mutex(), BOOL
HANDLE hMutex
hMutex = OpenMutex(MUTEX_ALL_ACCESS,0,GUIDstr())
if hMutex = 0
hMutex = CreateMutex(0,0,GUIDstr())
return TRUE
endif
CloseHandle(hMutex)
return FALSE
endf
' Following is for testing the app_mutex() function...
if app_mutex()
print "Accuired mutex!"
else
print "Already running!"
do:until inkey$<> ""
end
endif
do:until inkey$<> ""
|
|
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1226 Location: Morrison, CO, USA
|
Posted: Sat Dec 12, 2020 5:12 pm Post subject: |
|
|
Paul, it's always good to discover something new (?)! Actually, I enjoy digging deep, but sometimes it can be frustrating!
Yes, if the two names are unique, I can use this. I'll experiment to see if the icon resource I reference is different then the name follows this change. Could be useful, actually.
One problem I just uncovered with this scheme. I have a utility window that ends with %lw. After the window is created, I got the class name and it was "SalfordDialog_win_icon1". Closing the window, then starting it again and the class name is "SalfordDialog_win_icon2".
Luckily for me, the main window that always remains open is "0". I can live with that.
Something else to consider, something new!! [sarcasm]Oh joy![/sarcasm] |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1226 Location: Morrison, CO, USA
|
Posted: Sat Dec 12, 2020 5:34 pm Post subject: |
|
|
If I change the icon displayed, the "_win_icon" changes to match the resource name used, but the sequential number remains and increments with each invocation.
Each window that is started by my "standard" method increments this trailing number.
Windows that are not created as "invisible" do have the default class name. |
|
Back to top |
|
|
wahorger
Joined: 13 Oct 2014 Posts: 1226 Location: Morrison, CO, USA
|
Posted: Sat Dec 12, 2020 10:26 pm Post subject: |
|
|
More discoveries.
The format code %nc allows you to set the class name of a window after you set the icon (but only if the icon would be normally be displayed). However, I could only use this once and have that window open when the next window was created (menu selection for example). Stated another way, subsequent windows from this first open window that used the %nc format code were met with this error:
Quote: | Runtime error from program:f:\cmasterf95\release\win32\c-master.exe
Run-time Error
Unable to register class C-Master
004208d0 WINDOW_SETUP [+0209] This builds the next window preamble and sets the same %nc value
00489060 CIMPORT_NEW [+04db] Menu selection starts the function call which build a new window
00420c90 WINDOW_ENDING [+0290] This starts the main window where the %nc is first used
00401970 NEWMAIN [+10a8]
00401000 main [+095a]
|
So, one cannot use this %nc format code unless all other windows that use this format code have been closed.
That said, when the class name was displayed in the first routine (NEWMAIN) (before the runtime error) there is no "_win_icon#" present. This means the name I had assigned is exactly what I intended, and I can then use that name without ambiguity if the same program starts again! |
|
Back to top |
|
|
jalih
Joined: 30 Jul 2012 Posts: 196
|
Posted: Sun Dec 13, 2020 11:05 am Post subject: |
|
|
Keep in mind that using FindWindow() is not ideal, if there is possibility that multiple programs are started almost at the same time. It's not a bullet proof solution and might fail! |
|
Back to top |
|
|
|