Bladeren bron

Added RestartManager API unit + some testing.

Martijn Laan 13 jaren geleden
bovenliggende
commit
bdf7c69e8a
2 gewijzigde bestanden met toevoegingen van 216 en 1 verwijderingen
  1. 160 0
      Components/RestartManager.pas
  2. 56 1
      Projects/Main.pas

+ 160 - 0
Components/RestartManager.pas

@@ -0,0 +1,160 @@
+unit RestartManager;
+
+{
+  Basic RestartManager API interface Unit for Delphi 2 and higher
+  by Martijn Laan
+
+  $jrsoftware: issrc/Components/ScintInt.pas,v 1.3 2011/01/21 05:47:57 jr Exp $
+}
+
+{$IFNDEF VER90}
+{$IFNDEF VER93}
+  {$DEFINE Delphi3orHigher}
+{$ENDIF}
+{$ENDIF}
+
+interface
+
+uses
+  {$IFNDEF Delphi3orHigher} OLE2, {$ELSE} ActiveX, {$ENDIF}
+  Windows;
+
+procedure FreeRestartManagerLibrary;
+function InitRestartManagerLibrary: Boolean;
+function UseRestartManager: Boolean;
+
+const
+  RM_SESSION_KEY_LEN = SizeOf(TGUID);
+
+  CCH_RM_SESSION_KEY = RM_SESSION_KEY_LEN*2;
+
+  CCH_RM_MAX_APP_NAME = 255;
+
+  CCH_RM_MAX_SVC_NAME = 63;
+
+  RM_INVALID_TS_SESSION = -1;
+
+  RM_INVALID_PROCESS = -1;
+
+type
+  RM_APP_TYPE = DWORD;
+
+const
+  RmUnknownApp = 0;
+  RmMainWindow = 1;
+  RmOtherWindow = 2;
+  RmService = 3;
+  RmExplorer = 4;
+  RmConsole = 5;
+  RmCritical = 1000;
+
+type
+  RM_SHUTDOWN_TYPE = DWORD;
+
+const
+  RmForceShutdown = $01;
+  RmShutdownOnlyRegistered = $10;
+
+  //RM_APP_STATUS
+
+  //RM_REBOOT_REASON
+
+type
+  RM_UNIQUE_PROCESS = record
+    dwProcessId: DWORD;
+    ProcessStartTime: TFileTime;
+  end;
+
+  RM_PROCESS_INFO = record
+    Process: RM_UNIQUE_PROCESS;
+    strAppName: array[0..CCH_RM_MAX_APP_NAME] of WideChar;
+    strServiceShortName: array[0..CCH_RM_MAX_SVC_NAME] of WideChar;
+    ApplicationType: RM_APP_TYPE;
+    AppStatus: ULONG;
+    TSSessionId: DWORD;
+    bRestartable: BOOL;
+  end;
+
+  //RM_FILTER_TRIGGER
+
+  //RM_FILTER_ACTION
+
+  //RM_FILTER_INFO
+
+  //RM_WRITE_STATUS_CALLBACK
+
+var
+  RmStartSession: function (pSessionHandle: LPDWORD; dwSessionFlags: DWORD; strSessionKey: LPWSTR): DWORD; stdcall;
+
+  RmRegisterResources: function (dwSessionHandle: DWORD; nFiles: UINT; rgsFilenames: Pointer; nApplications: UINT; rgApplications: Pointer; nServices: UINT; rgsServiceNames: Pointer): DWORD; stdcall;
+
+  RmGetList: function (dwSessionHandle: DWORD; pnProcInfoNeeded, pnProcInfo: PUINT; rgAffectedApps: Pointer; lpdwRebootReasons: LPDWORD): DWORD; stdcall;
+
+  RmEndSession: function (dwSessionHandle: DWORD): DWORD; stdcall;
+
+implementation
+
+//----------------------------------------------------------------------------------------------------------------------
+
+const
+  restartmanagerlib = 'Rstrtmgr.dll';
+
+var
+  RestartManagerLibrary: THandle;
+  ReferenceCount: Integer;  // We have to keep track of several load/unload calls.
+
+procedure FreeRestartManagerLibrary;
+begin
+  if ReferenceCount > 0 then
+    Dec(ReferenceCount);
+
+  if (RestartManagerLibrary <> 0) and (ReferenceCount = 0) then
+  begin
+    FreeLibrary(RestartManagerLibrary);
+    RestartManagerLibrary := 0;
+
+    RmStartSession := nil;
+    RmRegisterResources := nil;
+    RmGetList := nil;
+    RmEndSession := nil;
+  end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function InitRestartManagerLibrary: Boolean;
+begin
+  Inc(ReferenceCount);
+
+  { Only attempt to load rstrtmgr.dll if running Windows Vista or later }
+  if (RestartManagerLibrary = 0) and (Lo(GetVersion) >= 6) then
+  begin
+    RestartManagerLibrary := LoadLibrary(restartmanagerlib);
+    if RestartManagerLibrary <> 0 then
+    begin
+      RmStartSession := GetProcAddress(RestartManagerLibrary, 'RmStartSession');
+      RmRegisterResources := GetProcAddress(RestartManagerLibrary, 'RmRegisterResources');
+      RmGetList := GetProcAddress(RestartManagerLibrary, 'RmGetList');
+      RmEndSession := GetProcAddress(RestartManagerLibrary, 'RmEndSession');
+    end;
+  end;
+  Result := RestartManagerLibrary <> 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function UseRestartManager: Boolean;
+
+begin
+  Result := RestartManagerLibrary <> 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+
+initialization
+finalization
+  while ReferenceCount > 0 do
+    FreeRestartManagerLibrary;
+
+end.

+ 56 - 1
Projects/Main.pas

@@ -18,7 +18,7 @@ interface
 uses
 uses
   Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
   Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
   SetupForm, StdCtrls, Struct, DebugStruct, Int64Em, CmnFunc, CmnFunc2,
   SetupForm, StdCtrls, Struct, DebugStruct, Int64Em, CmnFunc, CmnFunc2,
-  SetupTypes, ScriptRunner, BidiUtils;
+  SetupTypes, ScriptRunner, BidiUtils, RestartManager;
 
 
 type
 type
   TMainForm = class(TSetupForm)
   TMainForm = class(TSetupForm)
@@ -169,6 +169,8 @@ var
 {$IFDEF IS_D12}
 {$IFDEF IS_D12}
   TaskbarButtonHidden: Boolean;
   TaskbarButtonHidden: Boolean;
 {$ENDIF}
 {$ENDIF}
+  RmSessionHandle: DWORD;
+  RmSessionKey: array[0..CCH_RM_SESSION_KEY] of WideChar;
 
 
   CodeRunner: TScriptRunner;
   CodeRunner: TScriptRunner;
 
 
@@ -2637,6 +2639,9 @@ var
     end;
     end;
   end;
   end;
 
 
+type
+  TArrayOfPWideChar = array[0..(MaxInt div SizeOf(PWideChar))-1] of PWideChar;
+  PArrayOfPWideChar = ^TArrayOfPWideChar;
 var
 var
   ParamName, ParamValue: String;
   ParamName, ParamValue: String;
   StartParam: Integer;
   StartParam: Integer;
@@ -2652,6 +2657,10 @@ var
   LastShownComponentEntry, ComponentEntry: PSetupComponentEntry;
   LastShownComponentEntry, ComponentEntry: PSetupComponentEntry;
   MinimumTypeSpace: Integer64;
   MinimumTypeSpace: Integer64;
   SourceWildcard: String;
   SourceWildcard: String;
+  A: PArrayOfPWideChar;
+  S: String;
+  SLen, BLen, BLenNeeded, RebootReasons: Integer;
+  B: array[0..99] of RM_PROCESS_INFO;
 begin
 begin
   InitializeCommonVars;
   InitializeCommonVars;
 
 
@@ -3014,6 +3023,52 @@ begin
   if shEncryptionUsed in SetupHeader.Options then
   if shEncryptionUsed in SetupHeader.Options then
     LoadDecryptDLL;
     LoadDecryptDLL;
 
 
+  { Start RestartManagerSession }
+  InitRestartManagerLibrary;
+  if UseRestartManager then begin
+    if RmStartSession(@RmSessionHandle, 0, RmSessionKey) <> ERROR_SUCCESS then
+      FreeRestartManagerLibrary;
+  end;
+
+  if UseRestartManager then begin
+    GetMem(A, 2 * SizeOf(PWideChar));
+    for I := 0 to 1 do begin
+      if I = 0 then
+        S := 'c:\windows\explorer.exe'
+      else
+        S := 'c:\windows\notepad.exe';
+    {$IFNDEF UNICODE}
+      SLen := Length(S);
+      GetMem(A[I], (SLen + 1) * SizeOf(WideChar));
+      A[I][MultiByteToWideChar(CP_ACP, 0, PChar(S), SLen, A[I], SLen)] := #0;
+    {$ELSE}
+      A[I] := PWideChar(S);
+    {$ENDIF}
+  end;
+    if RmRegisterResources(RmSessionHandle, 2, A, 0, nil, 0, nil) <> ERROR_SUCCESS then begin
+      RmEndSession(RmSessionHandle);
+      FreeRestartManagerLibrary;
+    end;
+{$IFNDEF UNICODE}
+    FreeMem(A[0]);
+    FreeMem(A[1]);
+    FreeMem(A);
+{$ENDIF}
+  end;
+
+  if UseRestartManager then begin
+    BLen := High(B);
+    if RmGetList(RmSessionHandle, @BLenNeeded, @BLen, Addr(B), @RebootReasons) <> ERROR_SUCCESS then begin
+      RmEndSession(RmSessionHandle);
+      FreeRestartManagerLibrary;
+    end;
+  end;
+
+  if UseRestartManager then begin
+    if RmEndSession(RmSessionHandle) <> ERROR_SUCCESS then
+      FreeRestartManagerLibrary;
+  end;
+
   { Set install mode }
   { Set install mode }
   SetupInstallMode;
   SetupInstallMode;