فهرست منبع

Added RestartManager API unit + some testing.

Martijn Laan 13 سال پیش
والد
کامیت
bdf7c69e8a
2فایلهای تغییر یافته به همراه216 افزوده شده و 1 حذف شده
  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
   Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
   SetupForm, StdCtrls, Struct, DebugStruct, Int64Em, CmnFunc, CmnFunc2,
-  SetupTypes, ScriptRunner, BidiUtils;
+  SetupTypes, ScriptRunner, BidiUtils, RestartManager;
 
 type
   TMainForm = class(TSetupForm)
@@ -169,6 +169,8 @@ var
 {$IFDEF IS_D12}
   TaskbarButtonHidden: Boolean;
 {$ENDIF}
+  RmSessionHandle: DWORD;
+  RmSessionKey: array[0..CCH_RM_SESSION_KEY] of WideChar;
 
   CodeRunner: TScriptRunner;
 
@@ -2637,6 +2639,9 @@ var
     end;
   end;
 
+type
+  TArrayOfPWideChar = array[0..(MaxInt div SizeOf(PWideChar))-1] of PWideChar;
+  PArrayOfPWideChar = ^TArrayOfPWideChar;
 var
   ParamName, ParamValue: String;
   StartParam: Integer;
@@ -2652,6 +2657,10 @@ var
   LastShownComponentEntry, ComponentEntry: PSetupComponentEntry;
   MinimumTypeSpace: Integer64;
   SourceWildcard: String;
+  A: PArrayOfPWideChar;
+  S: String;
+  SLen, BLen, BLenNeeded, RebootReasons: Integer;
+  B: array[0..99] of RM_PROCESS_INFO;
 begin
   InitializeCommonVars;
 
@@ -3014,6 +3023,52 @@ begin
   if shEncryptionUsed in SetupHeader.Options then
     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 }
   SetupInstallMode;