Creating Restart Manager (RM) Aware Applications

Ever wondered how some applications are able to restart and just continue exactly where it left off? Well, I have. My curiosity knows no boundaries….

Today, you will learn how to make an RM Aware application. There is a lot of work, so let’s get started.

First, the complicated stuff.

API

The term API means Application Programming Interface. Any good program exposes some sort of API that can be used in other applications. Windows is no different. You have to remember that, in running Windows, you are indirectly executing code exposed by the Windows Operating System.

A simple action such as opening a file executes the desired functionality needed for the file to be run. Copying and pasting is another example.

Then, you get the functions running in the background that you usually do not have to care about: keeping track of memory usage, obtaining a list of running programs. I can go on.

Where Are These APIs Stored?

The Windows system, or any system for that matter, is made up out of a bunch of files, called DLLs amongst others. The term DLL means Dynamic Link Library. These files are dynamically linked with the Operating System to run the associated program with it. The methods of the programs are locked away in these files, and these methods make your applications work.

Now, to get back on topic. We need to make use of the specific methods inside the specific Windows DLL files to assist in your RM Aware applications.

Here is more information regarding APIs.

RM Aware

Some applications require a restart after they have been updated. Some applications require an entire system restart after installation, even after an uninstallation. Restart Manager enables all applications and services to be shut down and restarted. Enabling Restart Manager files that are in use get freed allows installation operations to complete. Restart Manager shuts down applications and services only if the caller has permission to do so. Here is more information on Restart Manager Aware applications.

Let’s create something, shall we?

Our Project

Create a new Visual Basic Windows Forms Project. You do not have to add anything to the form; leave it as is. Add a New class and name it anything you like. I have named mine ‘RM’. Add the following Namespaces to your ‘RM’ class:

Imports System
Imports System.Security
Imports System.Diagnostics
Imports System.ComponentModel
Imports System.Collections.Generic
Imports System.Runtime.InteropServices
Imports Microsoft.Win32.SafeHandles
Imports System.Security.Permissions
Imports System.Runtime.ConstrainedExecution
Imports System.Text

Some of these namespaces may seem new to you, so more information on these namespaces is in the next sections.

Microsoft.Win32.SafeHandles

The SafeHandles namespace provides common functionality supporting file and operating system handles.

System.Security.Permissions

The System.Security.Permissions namespace controls access to operations and resources based on policy.

System.Runtime.ConstrainedExecution

The System.Runtime.ConstrainedExecution namespace defines a contract for reliability between the author of some code and the developers who take a dependency on that code.

Continuing to Code

Add the following API functions to your class:

Public Class RM

   <DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _
      Public Shared Function RegisterApplicationRestart _
      (ByVal pszCommandline As String, _
      ByVal dwFlags As Integer) As UInteger
   End Function

   Public Shared Function RunningVistaOrLater() As Boolean
      Return System.Environment.OSVersion.Version.Major > 5
   End Function

   <DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _
      Friend Shared Function GetApplicationRestartSettings(ByVal hprocess _
      As IntPtr, ByVal pwzCommandline As IntPtr, ByRef pcchsize As UInteger, _
      ByVal pwzflag As IntPtr) As Integer
   End Function

   <DllImport("rstrtmgr.dll", CharSet:=CharSet.Auto)> _
      Friend Shared Function RmStartSession(ByRef pSessionHandle As UInteger, _
      ByVal dwSessionFlags As Integer, _
      ByVal strSessionKey As StringBuilder) As Integer
   End Function

   <DllImport("rstrtmgr.dll", CharSet:=CharSet.Auto)> _
      Friend Shared Function RmRegisterResources(ByVal pSessionHandle _
      As UInteger, ByVal nFiles As Integer, ByVal rgsFilenames As String(), _
      ByVal nApplications As Integer, ByVal rgApplications _
      As RM_UNIQUE_PROCESS(), ByVal nServices As Integer, _
      ByVal rgsServiceNames As String()) As Integer
   End Function

   <DllImport("rstrtmgr.dll", CharSet:=CharSet.Auto)> _
      Friend Shared Function RmShutdown(ByVal pSessionHandle As UInteger, _
      ByVal dwSessionFlags As UInteger, ByVal fnStatus As IntPtr) As Integer
   End Function

   <DllImport("rstrtmgr.dll", CharSet:=CharSet.Auto)> _
      Friend Shared Function RmRestart(ByVal pSessionHandle As UInteger, _
      ByVal dwRestartFlags As UInteger, ByVal fnStatus As IntPtr) As Integer
   End Function

   <DllImport("rstrtmgr.dll", CharSet:=CharSet.Auto)> _
      Friend Shared Function RmEndSession(ByVal pSessionHandle _
      As UInteger) As Integer
   End Function

End Class

Here is some more information on these APIs:

Add a new class to your project and replace the created code with the following Structure:

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Diagnostics
Imports System.Runtime.InteropServices.ComTypes

<System.Runtime.InteropServices.StructLayout _
   (System.Runtime.InteropServices.LayoutKind.Sequential)> _
   Friend Structure RM_UNIQUE_PROCESS
   Private dwProcessId As UInteger
   Private ProcessStartTime As FILETIME
   Friend Sub New(ByVal pid As Integer)
      dwProcessId = CInt(pid)
      Dim p As Process = Process.GetProcessById(pid)
      Dim dummy1 As FILETIME
      Dim dummy2 As FILETIME
      Dim dummy3 As FILETIME

      RM_UNIQUE_PROCESS.GetProcessTimes(p.Handle, ProcessStartTime, _
         dummy1, dummy2, dummy3)
   End Sub
   <System.Runtime.InteropServices.DllImport("kernel32.dll")> _
   Private Shared Sub GetProcessTimes(ByVal hprocess As IntPtr, _
   ByRef lpCreationTime As FILETIME, ByRef lpExitTime As FILETIME, _
   ByRef lpkernaltime As FILETIME, ByRef lpuserTime As FILETIME)
   End Sub
End Structure

Add the following code to your form to set things in motion:

Public Class frmRMAware

   Dim WM_QUERYENDSESSION As Int32 = 17
   Dim ENDSESSION_CLOSEAPP As Int32 = 1
   Dim WM_ENDSESSION As Int32 = 22



   Private Sub frmRMAware_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load

      If RM.RunningVistaOrLater Then

         RM.RegisterApplicationRestart("Test", 0)
      End If
   End Sub


   Protected Overloads Overrides Sub WndProc(ByRef msg _
         As System.Windows.Forms.Message)
      MyBase.WndProc(msg)

      If msg.Msg = WM_QUERYENDSESSION Or msg.Msg = WM_ENDSESSION Then
         If msg.LParam.ToString = ENDSESSION_CLOSEAPP Then

         End If
      End If
   End Sub
End Class

In the preceding code for frmRMAware, I have overridden the Load event to close and then restart the application.

Overriding

The term overriding means to give a new function to an existing function, thus replacing the function’s old methodology.

WndProc

WindowProc (or window procedure) is a user-defined callback function that processes messages sent to a window, here is more information on it:

https://msdn.microsoft.com/en-us/library/system.windows.forms.form.wndproc%28v=vs.110%29.aspx

Conclusion

Now that you are better versed in using RM Aware applications, I’m sure you’ll implement them in your coding. Cheers!

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read