用户登录计算机并运行我的应用程序。没有关闭应用程序,他只是切换用户。第二个用户登录并再次运行我的应用程序。
在这种情况下,我想从第二个实例中删除第一个实例而不向第一个用户进行任何暗示。
运行我的应用程序时,我在文本文件中写入实例的PID(在用户的通用路径中)。然后,我已经放置了一个计时器来跟踪文本文件中PID的变化。如果它与实例的PID不同,则实例将自行终止。
为了提高代码的性能,我想删除定时器逻辑。
注意:这两个用户都是普通用户,没有管理员权限
我尝试了以下方法,但没有成功。
方法1:按进程ID杀死
试图通过使用来自第二个用户实例的PID来终止第一个实例。能够获得第一个进程(ProcEntry)和terminateprocess并不会终止第一个实例,即使它不会抛出任何错误。
尝试设置权限(SE_DEBUG_NAME),但由于用户不是管理员而失败。
方法2:以互斥锁杀死 我没有得到足够的信息来杀死这个过程。
方法3:通过传递WIN API消息杀死
使用PostMessage方法无法在不同用户的应用程序之间传递消息。
方法4:使用命名管道
我不熟悉这种方法。
答案 0 :(得分:1)
一种方法是将进程ID保存在注册表中(而不是文件),然后监视它以进行任何更改。在线程(而不是计时器)内进行此监视,以便您不会将这些检查与主应用程序线程冲突。当线程检测到PID已经改变时,它就会自杀。
这是一个完整的例子:
unit uMain;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes,
Vcl.Forms, TlHelp32, Registry;
const
REG_KEY = 'Software\MyApp\';
type
TKillThread = class(TThread)
private
FPID: Integer;
FOnKill: TNotifyEvent;
protected
procedure Execute; override;
procedure SYNC_OnKill;
public
constructor Create(const PID: Integer);
property OnKill: TNotifyEvent read FOnKill write FOnKill;
end;
TfrmMain = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FKillThread: TKillThread;
procedure SavePID(const PID: Integer);
procedure Killed(Sender: TObject);
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
{ TKillThread }
constructor TKillThread.Create(const PID: Integer);
begin
inherited Create(True);
try
FPID:= PID;
finally
Resume;
end;
end;
procedure TKillThread.Execute;
var
P: Integer;
R: TRegistry;
begin
R:= TRegistry.Create(KEY_READ);
try
R.RootKey:= HKEY_LOCAL_MACHINE;
while not Terminated do begin
if R.KeyExists(REG_KEY) then begin
if R.OpenKey(REG_KEY, False) then begin
P:= R.ReadInteger('PID');
R.CloseKey;
end;
end;
if P <> FPID then begin
Synchronize(SYNC_OnKill);
end;
Sleep(100);
end;
finally
R.Free;
end;
end;
procedure TKillThread.SYNC_OnKill;
begin
if Assigned(FOnKill) then
FOnKill(Self);
end;
{ TfrmMain }
procedure TfrmMain.FormCreate(Sender: TObject);
begin
ReportMemoryLeaksOnShutdown:= True;
SavePID(GetCurrentProcessID);
FKillThread:= TKillThread.Create(GetCurrentProcessID);
FKillThread.OnKill:= Killed;
end;
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
FKillThread.Free;
end;
procedure TfrmMain.Killed(Sender: TObject);
begin
Application.Terminate;
end;
procedure TfrmMain.SavePID(const PID: Integer);
var
R: TRegistry;
begin
R:= TRegistry.Create(KEY_READ or KEY_WRITE);
try
R.RootKey:= HKEY_LOCAL_MACHINE;
if R.OpenKey(REG_KEY, True) then begin
R.WriteInteger('PID', PID);
R.CloseKey;
end;
finally
R.Free;
end;
end;
end.