两个常见的问题(让EXE文件只执行一次;如何在计算时可停止)(300分)

  • 主题发起人 主题发起人 gunwithlove
  • 开始时间 开始时间
G

gunwithlove

Unregistered / Unconfirmed
GUEST, unregistred user!
两个常见的问题:
我写了一个小程序,生成了一个EXE文件,双击它就会运行。请问如何防止多次双击而
多次运行它呢?(即如何防止同时运行多个该程序呢)
我写的这个程序的中有3个按钮,一个是“计算”,一个是“停止”,一个是“返回”,
因为计算比较烦琐,所以提供了停止计算的按钮,请问如何在计算的同时让用户可以点击
“停止”按钮呢?是不是必须要用多线程?有没有别的解决方案呢?
如果有相关例子,请贴出来参考一下,谢谢!
谢谢!
 
1 。
在项目文件中设置!
如下:
-----------------
program Project1;
uses
windows,
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
const classname='TForm1';
{声明为主窗体的类名}
var handle:integer;
{变量}
begin
handle:=findwindow(classname,nil);{查找是否有此类的窗体}
if handle<>0 then
{不为0则程序已运行}
begin
messagebox(0,'已经在运行中!','警告',0);
{提示程序已运行}
halt;
{退出程序}
end;

Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;

end.
---------------------------
注意 uses windows
调试程序时需要编译通过!
运行exe时要把delphi 关掉!
不然在IDE中得不到窗体!
 
1.http://www.delphibbs.com/delphibbs/dispq.asp?lid=438318
自己看一下,
2.就是使用多线程,具体看书吧,一两句也说不清楚.
 
第一个问题,有许多第三方控件可以解决,如LMD Tools等,或在你的程序初始化时,设置一个原子变量,
退出时销毁。启动时先对此变量进行查询,如果系统原子变量表已存在该变量,则退出。
例句:
if GlobalFindAtom('MY_PROGRAM_RUNNING') = 0 then
fAtom := GlobalAddAtom('MY_PROGRAM_RUNNING')
else
begin
{ 如果有同的程序则退出 }
Halt;
end;

第二个问题,用多线程+开关变量是最方便的方法。如果你的计算对系统资源占用很高,注意
对系统消息的处理。
 
以下是对第一个问题的回嘴。
program Project1;
uses
Forms,
windows,
Messages,
Unit1 in 'Unit1.pas' {Laihua};
const
CM_RESTORE = WM_USER + $1000;
Var
RvHandle : hWnd;
{$R *.RES}
begin
RvHandle := FindWindow('这是一个测试程序!', NIL);
if RvHandle > 0 then
begin
PostMessage(RvHandle, CM_RESTORE, 0, 0);
Exit;
end;
Application.Initialize;
Application.CreateForm(TLaihua, Laihua);
Application.Run;
end.
================================================================
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
const
CM_RESTORE = WM_USER + $1000;
//自定义窗口消息
type
TLaihua = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
procedure CreateParams(var Params: TCreateParams);
override;
Procedure RestoreRequest(var message: TMessage);
message CM_RESTORE;
end;

var
Laihua: TLaihua;

implementation
{$R *.DFM}
procedure TLaihua.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
//继承缺省的窗口创建过程
Params.WinClassName := '这是一个测试程序!';
//设置窗口类名称
end;

procedure TLaihua.RestoreRequest(var message: TMessage);
begin
if IsIconic(Application.Handle) = TRUE then
//如果程序是最小化为任务条上的图标时,将窗口恢复
Application.Restore
else
Application.BringToFront;
//否则将它被其它窗口遮住的程序主窗口带到前面来
end;

end.
=============================================================
2
你可以设置在按下停止后生成一个Flag ,然后的计算中判断它的状态,然后退出。

 
1、在工程文件中加入:
createmutex(nil,true,'zhwglxt.exe');
if getlasterror<>0 then
begin
application.MessageBox('系统已经运行!','错误信息',48);
exit;
end;
2、设置一个变量,在计算过程中不断检测这个变量的值
如 public status:smallint;

application.ProcessMessages;
//一定要加入这一句
if status>0 then
exit;
//计算
在停止中这样写
status:=1;
 
1、前面各位都说了,不再多嘴。
2、用线程是比较好的解决方法。继承一个线程类,然后在点击开始按钮时建立线程对象的
实体,点击中止按钮时调用线程的Terminate方法,但要避免重复建立线程对象,可采用互
斥对象Mutex来解决(就像楼上给出的避免程序重复执行的方法那样)
补充一下:在判断程序是否已经运行时,建议不要采用FindWindow的方法,因为这个方法
需要遍历系统中所有窗体的标题,在效率上不是很高,而且有可能找到不该找的窗体标题,
例如在IDE编辑环境下的窗体,从而带来一些麻烦;而且万一系统中还运行着另一个标题
(或窗体类名)与你的程序相同的程序,也会带来不可预料的结果(尽管这种可能性很小)
 
只运行一次可以用rxlib里的一个控件[:)]
 
除了窗口标题外,还可以用到互斥对象。
 
谢谢大家!
第一个问题,jrq和荷塘新月,Andisof的方法都很简单可行!
第二个问题,正在尝试!
 
第2个问题如果是循环计算也可以不用线程,直接用一个全局Boolean变量,
在计算时检查变量的值,如果是True,就计算,如果不是就停止。
在计算开始时赋True,按停止按钮赋False。
具体在计算时应加入Application.ProcessMessages;
好在计算期间,可以响应停止按钮的击键。
 
Application.ProcessMessages;但是对于大计算来说应该不是很好:)
上面有一些只能运行一个实例的方法,我就不多说了:)
我知道的方法有:互斥、内存映像、判断窗口等,如果你愿意甚至可以通过共享文件/流来
实现,只不过效果不好而已。
 
第一个问题用全局原子,如果程序非正常结束,那么程序的第二个实例也打不开。
 
多人接受答案了。
 
后退
顶部