注册 登录
编程论坛 VFP论坛

关于避免EXE重复运行的问题

laowan001 发布于 2023-10-10 09:05, 1304 次点击
程序代码:
DECLARE integer FindWindow  in   win32api   string   cClass,String   cCaption
if FindWindow(0,thisform.Caption)#0
    messagebox('本EXE已经运行')
endif

FindWindow(0,thisform.Caption)=0时,exe没有运行,如果大于0则表示已经运行
说明:执行的是编译后的EXE程序
问题:如果运行了程序,则FindWindow(0,thisform.Caption)非0,此时无法判断是否重复运行
解决办法:在setting.ini里写一个值,表示程序已经运行,程序退出时将这个值写为空,当再次运行时,判断这个值,如果是空则表示首次运行,否则就是重复运行
带来的问题:如果程序非正常退出,如断电、死机等,没能将那个值写为空,则以后再进入的时候则会判断为已经运行,至此卡住了

各位有什么好方法

28 回复
#2
星光悠蓝2023-10-10 10:16
用两个值来记录,一个记录是否运行,另一个记录是否正常退出,下次如果检测为非正常退出,则可正常运行。
#3
csyx2023-10-10 10:21
用 api 创建互斥量、信号灯、内存映射文件 ...,这其中任意一种方法都要可靠的多
#4
laowan0012023-10-10 10:40
以下是引用星光悠蓝在2023-10-10 10:16:07的发言:

用两个值来记录,一个记录是否运行,另一个记录是否正常退出,下次如果检测为非正常退出,则可正常运行。

“是否正常退出”,这个值只能在正常退出情况下能更新,非正常退出时没机会更新
“是否运行”也是同样的情况
好像还是没法明确判断
#5
laowan0012023-10-10 10:41
以下是引用csyx在2023-10-10 10:21:33的发言:

用 api 创建互斥量、信号灯、内存映射文件 ...,这其中任意一种方法都要可靠的多

这些方法我都不会
#6
abcde0072023-10-10 10:53
以下是引用laowan001在2023-10-10 10:40:46的发言:


“是否正常退出”,这个值只能在正常退出情况下能更新,非正常退出时没机会更新
“是否运行”也是同样的情况
好像还是没法明确判断



“非正常退出时没机会更新”,非正常退出这时候不需要更新啊。该数值没有更新恰恰说明是“非正常退出”吧。
“是否运行”也是一样的。

[此贴子已经被作者于2023-10-10 10:59编辑过]

#7
kangss2023-10-10 11:04
回复 5楼 laowan001
禁止程序重复运行的又一方法
DECLARE integer CreateEventA IN WIN32API integer,long,long,string
DECLARE integer OpenEventA IN WIN32API integer,long,string
IF OpenEventA(2031619, .F.,myappname)0 &&myappname可以是任意文本,最好要长一点。
    =MESSAGEBOX("程序已经在运行,不要浪费资源呵!", 48, "信息提示")
    RETURN .F.
ELSE
    CreateEventA(0, .F., .F.,myappname)
ENDIF

[此贴子已经被作者于2023-10-10 11:05编辑过]

#8
kangss2023-10-10 11:07
回复 楼主 laowan001
* 防止重复启动
DECLARE LONG CreateMutexA IN kernel32 LONG p1,LONG p2,STRING StrName
DECLARE LONG GetLastError IN kernel32

=CreateMutexA(0,0,"myexe123456")

IF GetLastError() = 183
    MESSAGEBOX('该程序已运行,不能重复运行!',48,'重复运行提示',4000)
    QUIT
ENDIF

CLEAR DLLS 'CreateMutexA','GetLastError'
#9
laowan0012023-10-10 11:46
以下是引用abcde007在2023-10-10 10:53:16的发言:




“非正常退出时没机会更新”,非正常退出这时候不需要更新啊。该数值没有更新恰恰说明是“非正常退出”吧。
“是否运行”也是一样的。

有道理!!!!!看来我是左脚绊右脚了
好像记录一个值就够了,我试下

[此贴子已经被作者于2023-10-10 11:48编辑过]

#10
csyx2023-10-10 11:53
使用互斥量检测的例子

程序代码:
Declare Long CreateMutex in win32api String, Long, String
Declare Long GetLastError in win32api

If (CreateMutex(Null, 1, 'mytest') != 0) and (GetLastError() == 183)
    MessageBox('重复运行', 16)
    Quit
Else
    MessageBox('首次运行' + 0h0d0a0d0a + '别关闭我,再次运行试试')
EndIf


编译后运行试试

#11
iswith2023-10-10 13:38
互斥 应该是最标准。。。。加锁也行。。。。
#12
laowan0012023-10-10 15:22
回复 8楼 kangss
方法可行,多谢多谢
#13
laowan0012023-10-10 15:24
以下是引用kangss在2023-10-10 11:04:06的发言:

禁止程序重复运行的又一方法
DECLARE integer CreateEventA IN WIN32API integer,long,long,string
DECLARE integer OpenEventA IN WIN32API integer,long,string
IF OpenEventA(2031619, .F.,myappname)0 &&myappname可以是任意文本,最好要长一点。
    =MESSAGEBOX("程序已经在运行,不要浪费资源呵!", 48, "信息提示")
    RETURN .F.
ELSE
    CreateEventA(0, .F., .F.,myappname)
ENDIF

测试未成功,代码中的myappname换成exe文件名(如:aaa.exe),同时两次运行同一exe,OpenEventA(2031619, .F.,myappname)的值均为0,不知我的操作是否正确
其中的2031619是固定值吧?

[此贴子已经被作者于2023-10-10 15:26编辑过]

#14
laowan0012023-10-10 15:25
回复 10楼 csyx
方法可行,多谢多谢
#15
iswith2023-10-10 17:57
互斥,它少了一步。。。
#16
csyx2023-10-10 21:06
以下是引用iswith在2023-10-10 17:57:33的发言:

互斥,它少了一步。。。

是的,QUIT 前应加一条 CloseHandle
#17
laowan0012023-10-11 08:35
以下是引用csyx在2023-10-10 21:06:28的发言:


是的,QUIT 前应加一条 CloseHandle

正确!!!
#18
laowan0012023-10-11 08:41
以下是引用星光悠蓝在2023-10-10 10:16:07的发言:

用两个值来记录,一个记录是否运行,另一个记录是否正常退出,下次如果检测为非正常退出,则可正常运行。

我脑子都转筋了还是没想明白
程序执行起来,是否运行=是,正常退出=否,这时断电了,那么再执行程序时看这两个变量的话,还是运行且未退出状态,仍然没法判断是否重复了
#19
yiyanxiyin2023-10-11 09:42
以下是引用laowan001在2023-10-11 08:41:46的发言:


我脑子都转筋了还是没想明白
程序执行起来,是否运行=是,正常退出=否,这时断电了,那么再执行程序时看这两个变量的话,还是运行且未退出状态,仍然没法判断是否重复了



这种方法是不行的, 因为非正常退出你没法记录状态, 和正在运行没法区别, 你可以搞个心跳, 比如每一秒记录一下当前时间(心跳时间), 表示它没死,  程序启动时检查心跳时间, 如果和现在的时间间隔超过2秒就允许启动,否则就不让启动


当然, 微软有标准api来判断, 产品里面还是使用标准的来吧, 自己琢磨搞着玩可以试试自己的方法

[此贴子已经被作者于2023-10-11 09:52编辑过]

#20
laowan0012023-10-11 09:59
以下是引用yiyanxiyin在2023-10-11 09:42:38的发言:




这种方法是不行的, 因为非正常退出你没法记录状态, 和正在运行没法区别, 你可以搞个心跳, 比如每一秒记录一下当前时间(心跳时间), 表示它没死,  程序启动时检查心跳时间, 如果和现在的时间间隔超过2秒就允许启动,否则就不让启动


当然, 微软有标准api来判断, 产品里面还是使用标准的来吧, 自己琢磨搞着玩可以试试自己的方法

这个方法可行,就是有点麻烦,感谢回复

[此贴子已经被作者于2023-10-11 15:11编辑过]

#21
shonken2023-10-12 11:45
以下是引用csyx在2023-10-10 21:06:28的发言:


是的,QUIT 前应加一条 CloseHandle


继续请教下,具体怎么加CloseHandle?

是注册API,然后CloseHandle(0)?
#22
csyx2023-10-12 12:08
以下是引用shonken在2023-10-12 11:45:59的发言:
具体怎么加CloseHandle?
是注册API,然后CloseHandle(0)?

意思大概是这样:
程序代码:
Declare Long CreateMutex in win32api String, Long, String
Declare Long GetLastError in win32api
Declare Long CloseHandle in win32api Long

Local hMutex

m.hMutex = CreateMutex(Null, 1, 'mytest')
If (m.hMutex != 0) and (GetLastError() == 183)
    CloseHandle(m.hMutex)
    MessageBox('重复运行')
    Quit
Else
    MessageBox('首次运行' + 0h0d0a0d0a + '别关闭我,再次运行试试')
EndIf


我也不确定15楼说的是不是这一步?如果是,则并非必要,加上它仅仅是出于遵循良好的编程习惯
重复运行时,CreateMutex 得到的句柄副本也属于系统资源,操作系统会自动清理任何被终止进程未释放的资源。这个api多用于多线程间的同步/互锁,如果是用于线程,是需要主动关闭以避免引用计数混乱的,但这里是用于进程
#23
shonken2023-10-12 16:18
以下是引用csyx在2023-10-12 12:08:58的发言:


意思大概是这样:
Declare Long CreateMutex in win32api String, Long, String
Declare Long GetLastError in win32api
Declare Long CloseHandle in win32api Long

Local hMutex

m.hMutex = CreateMutex(Null, 1, 'mytest')
If (m.hMutex != 0) and (GetLastError() == 183)
    CloseHandle(m.hMutex)
    MessageBox('重复运行')
    Quit
Else
    MessageBox('首次运行' + 0h0d0a0d0a + '别关闭我,再次运行试试')
EndIf


我也不确定15楼说的是不是这一步?如果是,则并非必要,加上它仅仅是出于遵循良好的编程习惯
重复运行时,CreateMutex 得到的句柄副本也属于系统资源,操作系统会自动清理任何被终止进程未释放的资源。这个api多用于多线程间的同步/互锁,如果是用于线程,是需要主动关闭以避免引用计数混乱的,但这里是用于进程


学习了。之前测试时加不加CloseHandle都能判断重复运动。
#24
esailor2023-10-24 09:41
学习,多谢!
#25
sych2023-10-24 10:10
public mmtitle,hfile
mmtitle="随便起个名字吧"
if IsRunAgain()
    MESSAGEBOX("程序已经在运行,请检查!",64+4096,"温馨提示")
    quit
ENDIF
return

Function IsRunAgain
Declare Long OpenFileMapping In WIN32API Long, Long, String
Declare Long CreateFileMapping In WIN32API Long, Long, Long, Long, Long, String
DECLARE INTEGER CloseHandle IN kernel32.DLL INTEGER hObject
cPID = mmtitle
hFile = OpenFileMapping(4, 0, cPID)
If hFile=0
    hFile = CreateFileMapping(-1, 0, 4, 0, 1+Len(cPID), cPID+Chr(0))
    Return .F.
Else
    =CloseHandle(hFile)
    Return .T.
Endif
Endfunc

#26
esailor2023-10-24 11:00
不错,不错,多谢!
#27
pvm20002023-10-25 12:30
简单的文件互斥,也可以解决问题
#28
sam_jiang2023-10-25 20:34
很简单,程序启动时,任意建立一个文件,可以为空,程序结束时删除它。

每次程序启动时,检查这个文件是否存在,如果存在,说明是非正常退出。

至于程序是否已运行,用findwidow就可以了。。。
#29
Pgwyg2023-12-17 06:43
*main.prg
*-防止程序重复运行的代码
_screen.Visible = .f.
_screen.windowstate=1
DECLARE integer FindWindow in Win32Api String, String
wclass=0
winname="水表(流量计)远程数据采集系统"
apphand = FindWindow(wclass ,winname)
IF apphand<>0
    Messagebox("程序已经运行!",48,"系统信息")
    QUIT
ENDIF
MODIFY WINDOW screen TITLE "水表(流量计)远程数据采集系统"

*系统设置
1