Einzelnen Beitrag anzeigen

Der schöne Günther

Registriert seit: 6. Mär 2013
6.110 Beiträge
 
Delphi 10 Seattle Enterprise
 
#11

AW: CreateProcess und gestarteten Prozess automatisch beenden wenn Anwendung beendet

  Alt 19. Sep 2014, 18:01
Falls es nochmal jemanden interessiert:

Ich habe das ganze mal in einen etwas komfortableren Wrapper gepackt. Die Benutzung sieht dann so aus:

Delphi-Quellcode:
begin
   jobObj := TWinJob.Create('meinJob');
   jobObj.KillContainingProcessesOnExit := True;

   // [Prozess mit CREATE_BREAKAWAY_FROM_JOB-Flag erstellen]

   jobObj.moveProcessTo(dasProzessHandle);

   ReadLn;

   jobObj.Free(); // Damit wird der Prozess wieder geschlossen
end.


Die passende Unit:
Delphi-Quellcode:
unit WindowsJob platform;

interface uses Winapi.Windows, WinAPI_Job_Header;

type

   /// <summary>
   /// Repräsentiert einen Windows-Job- Siehe
   /// <see href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms684161(v=vs.85).aspx">
   /// MSDN: Job Objects
   /// </see>.
    /// </summary>
   TWinJob = class
      public type
         TProcessHandle = Winapi.Windows.THandle;
         TJobHandle = Winapi.Windows.THandle;

      private
         /// <seealso cref="KillContainingProcessesOnExit" />
         FKillContainingProcessesOnExit: Boolean;

      protected var
         /// <seealso cref="JobHandle" />
         FJobHandle: TJobHandle;
         /// <remarks>
         /// Wird kein Name verwendet entspricht der Wert des Feldes
         /// <c>EmptyStr</c>
            /// </remarks>
         jobName: String;

         /// <summary>
         /// Enthält die
         /// <see href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms684156(v=vs.85).aspx">
         ///    JOBOBJECT_EXTENDED_LIMIT_INFORMATION
         /// </see>-Informationen des Jobs. Wird von
         /// <see cref="queryJobInformation" /> abgefragt.
         /// </summary>
         /// <seealso cref="KillContainingProcessesOnExit" />
         extInfo: TJobObjectExtendedLimitInformation;

      protected
         /// <summary>
         /// Prüft, ob das in <see cref="JobHandle" /> abgelegte
         /// Handle auf eine fehlgeschlagene Job-Erstellung hindeutet.
         /// In diesem Fall wird eine <c>EOSError</c>-Exception
         /// geworfen
         /// </summary>
            /// <exception cref="EOSError" />
         procedure checkJobHandle();
         /// <summary>
         /// Aktualisiert die <c>ExtendedLimitInformation</c> dieses
         /// Jobs und legt diese im Feld
         /// <see cref="extInfo" /> ab.
            /// </summary>
         procedure queryJobInformation(); virtual;
         procedure setKillContainingProcessesOnExit(const Value: Boolean);

      public
         constructor Create(); overload;
         /// <exception cref="EOSError">
         /// Wenn bereits ein event, semaphore, mutex, waitable timer oder
         /// file-mapping mit dem gleichen Namen existiert
         /// </exception>
         constructor Create(const jobName: String); overload;
            destructor Destroy(); override;

         /// <returns>
         /// Gibt an ob der Prozess erfolgreich in diesen Job
         /// verschoben werden konnte
         /// </returns>
         /// <remarks>
         /// Der mit <c>CreateProcess</c> erstellte Prozess muss mit dem
         /// <see cref="WinAPI_Job_Header.CREATE_BREAKAWAY_FROM_JOB" />-Flag
         /// in seinem <c>dwCreationFlags</c>-Parameter erstellt werden.
            /// Ansonsten schlägt die Methode fehl und gibt <c>False</c> zurück
         /// </remarks>
         function moveProcessTo(const processHandle: TProcessHandle): Boolean;

      public // properties
         /// <summary>
         /// Gibt an ob die im Job enthaltenen Prozesse <b>beim Schließen
         /// des letzten Handles auf den Job</b> vom Betriebssystem
         /// terminiert werden sollen
         /// </summary>
         property KillContainingProcessesOnExit: Boolean
            read FKillContainingProcessesOnExit
            write setKillContainingProcessesOnExit;

         property JobHandle: TJobHandle
            read FJobHandle;
   end;

implementation uses System.SysUtils;

{ TWinJob }

constructor TWinJob.Create();
begin
   inherited Create();

   FJobHandle := CreateJobObject(nil, nil);
   jobName := EmptyStr;
   checkJobHandle();
end;

procedure TWinJob.checkJobHandle();
var
   lastError: DWORD;
begin
   if (jobHandle = 0) then begin
      lastError := GetLastError();
      case lastError of
         ERROR_INVALID_HANDLE: raise {$REGION 'EOSError'}
            EOSError.Create(
               'An event, semaphore, mutex, waitable timer, or file-mapping '
               +'with the same name of "'+jobName+'" already '
               +'exists. Cannot create Job.'
            );
         {$ENDREGION 'EOSError'}
      else
         SetLastError(lastError);
         RaiseLastOSError();
      end;
   end;
end;

constructor TWinJob.Create(const jobName: String);
begin
   inherited Create();
   self.jobName := jobName;

   FJobHandle := CreateJobObject(nil, PChar(jobName));
   checkJobHandle();
end;


destructor TWinJob.Destroy();
begin
   CloseHandle(jobHandle);
   inherited;
end;

function TWinJob.moveProcessTo(const processHandle: TProcessHandle): Boolean;
begin
   Result := AssignProcessToJobObject(jobHandle, processHandle);
end;

procedure TWinJob.queryJobInformation();
begin
   Win32Check(
      QueryInformationJobObject(
         jobHandle,
         TJobObjectInfoClass.ExtendedLimitInformation,
         Addr(extInfo),
         SizeOf(extInfo),
         nil
      )
   );
end;

procedure TWinJob.setKillContainingProcessesOnExit(const Value: Boolean);
const
   queryFirst: Boolean = True;
var
   basicInfo: TJobObjectBasicLimitInformation;
begin
   FKillContainingProcessesOnExit := Value;

   if queryFirst then queryJobInformation();
   basicInfo := extInfo.BasicLimitInformation;

   if KillContainingProcessesOnExit then
      basicInfo.LimitFlags := basicInfo.LimitFlags or JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
   else
      basicInfo.LimitFlags := basicInfo.LimitFlags and (not JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE);

   extInfo.BasicLimitInformation := basicInfo;

   Win32Check(
      SetInformationJobObject(
         jobHandle,
         TJobObjectInfoClass.ExtendedLimitInformation,
         Addr(extInfo),
         SizeOf(extInfo)
      )
   );
end;

end.
  Mit Zitat antworten Zitat