Autor Téma: Neuvolněný mutex službou  (Přečteno 97 krát)

Offline gully

  • Nováček
  • *
  • Příspěvků: 12
  • Karma: 0
    • Verze Delphi: D7 Professional
    • Offline verze seriálu o programování v Delphi
Neuvolněný mutex službou
« kdy: 10-11-2019, 16:13:50 »
Ahoj všem :)

Vytvářím službu, která přes Mutex kontroluje, jestli je/není spuštěná aplikace a v případě, že není, tak ji spustí. Nedaří se mi v ní ale správně otestovat, jestli je daný Mutex vytvořený, nebo ne. V okamžiku, kdy danou aplikaci ukončím, služba jakoby podrží mutex v paměti, takže nedojde k jejímu spuštění. Pokud se pokusím v této době spustit apku ručně, hlásí, že je již spuštěna. K testování, po různých pokusech (zkoušel jsem i fci. OpenMutex), používám aktuálně tento kód:

Kód: Delphi [Vybrat]
  1. procedure TService1.tmrTimerTimer(Sender: TObject);
  2.  var
  3.   I: integer;
  4.   MutexName, ExeFullPath: string;
  5.   HMutex: THandle;
  6. begin
  7.   for I := Low(AAppInfo) to High(AAppInfo) do
  8.   begin
  9.     MutexName := AAppInfo[I].MutexName;
  10.     HMutex := CreateMutex(nil, false, PChar(MutexName));
  11.     if (GetLastError <> ERROR_ALREADY_EXISTS) then
  12.     begin
  13.       ReleaseMutex(HMutex);
  14.       CloseHandle(HMutex);
  15.       ExeFullPath := IncludeTrailingPathDelimiter(AAppInfo[I].ExePath) + AAppInfo[I].ExeName;
  16.       ShellExecute(0, 'open', Pchar(ExeFullPath), nil, nil, SW_SHOWNORMAL) ;
  17.     end;
  18.   end;
  19. end;

Nesetkal jste se někdo s podobným problémem a nevíte, jak ho vyřešit?
« Poslední změna: 10-11-2019, 16:20:22 od gully »

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2607
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:Neuvolněný mutex službou
« Odpověď #1 kdy: 10-11-2019, 16:41:29 »
    HMutex := CreateMutex(nil, false, PChar(MutexName));
    if (GetLastError <> ERROR_ALREADY_EXISTS) then
Tohle bys mel otestovat poradne tj. nejprve vracenou hodnotu a pak teprve rozsirene info, protoze muze nastat situace, kdy to vrati 0 a napr.  ERROR_ACCESS_DENIED, coz by u sluzby mohlo byt dost pravdepodobne - jestli si to pamatuju, tak ve sluzbach jsme pouzivali create "accessible" object tj. neco takoveho
Kód: Delphi [Vybrat]
  1.     var
  2.       Sa: TSecurityAttributes;
  3.       Sd: TSecurityDescriptor;
  4.     begin
  5.       Win32Check(InitializeSecurityDescriptor(@Sd, SECURITY_DESCRIPTOR_REVISION));
  6.       Win32Check(SetSecurityDescriptorDacl(@Sd, True, nil, False));
  7.       Sa.nLength := SizeOf(Sa);
  8.       Sa.lpSecurityDescriptor := @Sd;
  9.       Sa.bInheritHandle := False;
  10.       Result := CreateMutex(@Sa, InitialOwner, PChar(Name));
  11.     end;
  12.  

Offline gully

  • Nováček
  • *
  • Příspěvků: 12
  • Karma: 0
    • Verze Delphi: D7 Professional
    • Offline verze seriálu o programování v Delphi
Re:Neuvolněný mutex službou
« Odpověď #2 kdy: 10-11-2019, 18:10:59 »
Máš pravdu, standardní testování nestačí. Nakonec jsem použil hotové řešení na stejném principu ze Stack Overflow.

Pro úplnost sem vkládám kód:
Kód: Delphi [Vybrat]
  1. //Creates a mutex to see if the program is already running.
  2. function IsSingleInstance(MutexName : string; KeepMutex : boolean = true):boolean;
  3.  
  4. var MutexHandel : THandle;
  5.     SecurityDesc: TSecurityDescriptor;
  6.     SecurityAttr: TSecurityAttributes;
  7.     ErrCode : integer;
  8. begin
  9.   //  By default (lpMutexAttributes =nil) created mutexes are accessible only by
  10.   //  the user running the process. We need our mutexes to be accessible to all
  11.   //  users, so that the mutex detection can work across user sessions.
  12.   //  I.e. both the current user account and the System (Service) account.
  13.   //  To do this we use a security descriptor with a null DACL.
  14.   InitializeSecurityDescriptor(@SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
  15.   SetSecurityDescriptorDacl(@SecurityDesc, True, nil, False);
  16.   SecurityAttr.nLength:=SizeOf(SecurityAttr);
  17.   SecurityAttr.lpSecurityDescriptor:=@SecurityDesc;
  18.   SecurityAttr.bInheritHandle:=False;
  19.  
  20.   //  The mutex is created in the global name space which makes it possible to
  21.   //  access across user sessions.
  22.   MutexHandel := CreateMutex(@SecurityAttr, True, PChar(MutexName));
  23.   ErrCode := GetLastError;
  24.  
  25.   //  If the function fails, the return value is 0
  26.   //  If the mutex is a named mutex and the object existed before this function
  27.   //  call, the return value is a handle to the existing object, GetLastError
  28.   //  returns ERROR_ALREADY_EXISTS.
  29.   if {(MutexHandel = 0) or }(ErrCode = ERROR_ALREADY_EXISTS) then
  30.   begin
  31.     result := false;
  32.     closeHandle(MutexHandel);
  33.   end
  34.   else
  35.   begin
  36.     //  Mutex object has not yet been created, meaning that no previous
  37.     //  instance has been created.
  38.     result := true;
  39.  
  40.     if not KeepMutex then
  41.        CloseHandle(MutexHandel);
  42.   end;
  43.  
  44.   // The Mutexhandle is not closed because we want it to exist during the
  45.   // lifetime of the application. The system closes the handle automatically
  46.   //when the process terminates.
  47. end;
« Poslední změna: 10-11-2019, 18:13:53 od gully »