diff --git a/LockChecker/LockCheck.vb b/LockChecker/LockCheck.vb
new file mode 100644
index 0000000..bce827f
--- /dev/null
+++ b/LockChecker/LockCheck.vb
@@ -0,0 +1,233 @@
+' code sample taken from:
+'https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-170ed5f3/sourcecode?fileId=151114&pathId=1558127374
+' Modified to suit the needs of this application
+Imports System.ComponentModel
+Imports System.Runtime.InteropServices
+
+Module LockCheck
+ ' maximum character count of application friendly name.
+ Private Const CCH_RM_MAX_APP_NAME As Integer = 255
+ ' maximum character count of service short name.
+ Private Const CCH_RM_MAX_SVC_NAME As Integer = 63
+ ' A system restart is not required.
+ Private Const RmRebootReasonNone As Integer = 0
+
+ '''
+ ''' Uniquely identifies a process by its PID and the time the process began.
+ ''' An array of RM_UNIQUE_PROCESS structures can be passed
+ ''' to the RmRegisterResources function.
+ '''
+
+ Private Structure RM_UNIQUE_PROCESS
+ ' The product identifier (PID).
+ Public dwProcessId As Integer
+ ' The creation time of the process.
+ Public ProcessStartTime As System.Runtime.InteropServices.ComTypes.FILETIME
+ End Structure
+
+ '''
+ ''' Specifies the type of application that is described by
+ ''' the RM_PROCESS_INFO structure.
+ '''
+ Private Enum RM_APP_TYPE
+ ' The application cannot be classified as any other type.
+ RmUnknownApp = 0
+ ' A Windows application run as a stand-alone process that
+ ' displays a top-level window.
+ RmMainWindow = 1
+ ' A Windows application that does not run as a stand-alone
+ ' process and does not display a top-level window.
+ RmOtherWindow = 2
+ ' The application is a Windows service.
+ RmService = 3
+ ' The application is Windows Explorer.
+ RmExplorer = 4
+ ' The application is a stand-alone console application.
+ RmConsole = 5
+ ' A system restart is required to complete the installation because
+ ' a process cannot be shut down.
+ RmCritical = 1000
+ End Enum
+
+ '''
+ ''' Describes an application that is to be registered with the Restart Manager.
+ '''
+
+ Private Structure RM_PROCESS_INFO
+ ' Contains an RM_UNIQUE_PROCESS structure that uniquely identifies the
+ ' application by its PID and the time the process began.
+ Public Process As RM_UNIQUE_PROCESS
+ ' If the process is a service, this parameter returns the
+ ' long name for the service.
+
+ Public strAppName As String
+ ' If the process is a service, this is the short name for the service.
+
+ Public strServiceShortName As String
+ ' Contains an RM_APP_TYPE enumeration value.
+ Public ApplicationType As RM_APP_TYPE
+ ' Contains a bit mask that describes the current status of the application.
+ Public AppStatus As UInteger
+ ' Contains the Terminal Services session ID of the process.
+ Public TSSessionId As UInteger
+ ' TRUE if the application can be restarted by the
+ ' Restart Manager; otherwise, FALSE.
+
+ Public bRestartable As Boolean
+ End Structure
+
+ '''
+ ''' Registers resources to a Restart Manager session. The Restart Manager uses
+ ''' the list of resources registered with the session to determine which
+ ''' applications and services must be shut down and restarted. Resources can be
+ ''' identified by filenames, service short names, or RM_UNIQUE_PROCESS structures
+ ''' that describe running applications.
+ '''
+ '''
+ ''' A handle to an existing Restart Manager session.
+ '''
+ ''' The number of files being registered
+ '''
+ ''' An array of null-terminated strings of full filename paths.
+ '''
+ ''' The number of processes being registered
+ ''' An array of RM_UNIQUE_PROCESS structures
+ ''' The number of services to be registered
+ '''
+ ''' An array of null-terminated strings of service short names.
+ '''
+ ''' The function can return one of the system error codes that
+ ''' are defined in Winerror.h
+ '''
+
+ Private Function RmRegisterResources(pSessionHandle As UInteger, nFiles As UInt32, rgsFilenames As String(), nApplications As UInt32, <[In]> rgApplications As RM_UNIQUE_PROCESS(), nServices As UInt32,
+ rgsServiceNames As String()) As Integer
+ End Function
+
+ '''
+ ''' Starts a new Restart Manager session. A maximum of 64 Restart Manager
+ ''' sessions per user session can be open on the system at the same time.
+ ''' When this function starts a session, it returns a session handle and
+ ''' session key that can be used in subsequent calls to the Restart Manager API.
+ '''
+ '''
+ ''' A pointer to the handle of a Restart Manager session.
+ '''
+ ''' Reserved. This parameter should be 0.
+ '''
+ ''' A null-terminated string that contains the session key to the new session.
+ '''
+ '''
+
+ Private Function RmStartSession(ByRef pSessionHandle As UInteger, dwSessionFlags As Integer, strSessionKey As String) As Integer
+ End Function
+
+ '''
+ ''' Ends the Restart Manager session. This function should be called by the
+ ''' primary installer that has previously started the session by calling the
+ ''' RmStartSession function. The RmEndSession function can be called by a
+ ''' secondary installer that is joined to the session once no more resources
+ ''' need to be registered by the secondary installer.
+ '''
+ '''
+ ''' A handle to an existing Restart Manager session.
+ '''
+ '''
+ ''' The function can return one of the system error codes
+ ''' that are defined in Winerror.h.
+ '''
+
+ Private Function RmEndSession(pSessionHandle As UInteger) As Integer
+ End Function
+
+ '''
+ ''' Gets a list of all applications and services that are currently using
+ ''' resources that have been registered with the Restart Manager session.
+ '''
+ '''
+ ''' A handle to an existing Restart Manager session.
+ '''
+ ''' A pointer to an array size necessary to
+ ''' receive RM_PROCESS_INFO structures required to return information for
+ ''' all affected applications and services.
+ '''
+ '''
+ ''' A pointer to the total number of RM_PROCESS_INFO structures in an array
+ ''' and number of structures filled.
+ '''
+ '''
+ ''' An array of RM_PROCESS_INFO structures that list the applications and
+ ''' services using resources that have been registered with the session.
+ '''
+ '''
+ ''' Pointer to location that receives a value of the RM_REBOOT_REASON
+ ''' enumeration that describes the reason a system restart is needed.
+ '''
+ '''
+
+ Private Function RmGetList(dwSessionHandle As UInteger, ByRef pnProcInfoNeeded As UInteger, ByRef pnProcInfo As UInteger, <[In], Out> rgAffectedApps As RM_PROCESS_INFO(), ByRef lpdwRebootReasons As UInteger) As Integer
+ End Function
+
+ Function LockCheck(Filename As String)
+ Dim handle As UInteger
+ Dim sessionkey As String = Guid.NewGuid().ToString()
+ Dim processes As New List(Of Process)()
+ Dim result As String = ""
+
+ Dim res As Integer = RmStartSession(handle, 0, sessionkey)
+ If res <> 0 Then
+ Throw New Exception("Could not begin restart session.")
+ End If
+
+ Try
+ Dim pnProcInfoNeeded As UInteger = 0, pnProcInfo As UInteger = 100, lpdwRebootReasons As UInteger = RmRebootReasonNone
+ Dim resources As String() = New String() {Filename}
+
+ ' Create an array to store the process results.
+ Dim processInfo As RM_PROCESS_INFO() = New RM_PROCESS_INFO(pnProcInfo - 1) {}
+
+ res = RmRegisterResources(handle, CUInt(resources.Length), resources, 0, Nothing, 0,
+ Nothing)
+ If res <> 0 Then
+ Throw New Exception("Could not register resource.")
+ End If
+
+ res = RmGetList(handle, pnProcInfoNeeded, pnProcInfo, processInfo, lpdwRebootReasons)
+ If res = 0 Then
+ 'The function completed successfully.
+
+ If pnProcInfo <> 0 Then
+ For i As Integer = 0 To pnProcInfo - 1
+ 'Console.WriteLine("File Name :" + resources(0))
+ result = result + "File Name :" + resources(0) + vbNewLine
+ 'Console.WriteLine("Application locking the file :" + processInfo(i).strAppName)
+ result = result + "Application locking the file : " + processInfo(i).strAppName + vbNewLine
+ result = result + "PID of process locking the file: " + processInfo(i).Process.dwProcessId.ToString() + vbNewLine
+ Next
+ Else
+ 'Console.WriteLine("The specified file '{0}' is not locked by any process", resources(0))
+ result = result + "No locks"
+
+ End If
+ Else
+ Throw New Exception("Could not list processes locking resource.")
+ End If
+
+ If res <> 0 Then
+ Throw New Win32Exception(Marshal.GetLastWin32Error())
+
+ End If
+ Catch exception As Exception
+ 'Console.WriteLine(exception.Message)
+ result = result + exception.Message
+ Finally
+ RmEndSession(handle)
+ End Try
+ Return result
+ End Function
+End Module
+Public Class LockChecker
+ Public Function CheckLock(FileName As String)
+ Return LockCheck.LockCheck(FileName)
+ End Function
+End Class
\ No newline at end of file
diff --git a/LockChecker/LockChecker.vbproj b/LockChecker/LockChecker.vbproj
new file mode 100644
index 0000000..d9eb626
--- /dev/null
+++ b/LockChecker/LockChecker.vbproj
@@ -0,0 +1,102 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {029C010D-728B-4B87-B54A-08B2BBF49BD7}
+ Library
+ LockChecker
+ LockChecker
+ 512
+ Windows
+ v4.0
+ true
+
+
+ true
+ full
+ true
+ true
+ bin\Debug\
+ LockChecker.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ pdbonly
+ false
+ true
+ true
+ bin\Release\
+ LockChecker.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ On
+
+
+ Binary
+
+
+ Off
+
+
+ On
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ Application.myapp
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+ VbMyResourcesResXFileCodeGenerator
+ Resources.Designer.vb
+ My.Resources
+ Designer
+
+
+
+
+ MyApplicationCodeGenerator
+ Application.Designer.vb
+
+
+ SettingsSingleFileGenerator
+ My
+ Settings.Designer.vb
+
+
+
+
\ No newline at end of file
diff --git a/LockChecker/My Project/Application.Designer.vb b/LockChecker/My Project/Application.Designer.vb
new file mode 100644
index 0000000..88dd01c
--- /dev/null
+++ b/LockChecker/My Project/Application.Designer.vb
@@ -0,0 +1,13 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
diff --git a/LockChecker/My Project/Application.myapp b/LockChecker/My Project/Application.myapp
new file mode 100644
index 0000000..758895d
--- /dev/null
+++ b/LockChecker/My Project/Application.myapp
@@ -0,0 +1,10 @@
+
+
+ false
+ false
+ 0
+ true
+ 0
+ 1
+ true
+
diff --git a/LockChecker/My Project/AssemblyInfo.vb b/LockChecker/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..8e94d0f
--- /dev/null
+++ b/LockChecker/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' General Information about an assembly is controlled through the following
+' set of attributes. Change these attribute values to modify the information
+' associated with an assembly.
+
+' Review the values of the assembly attributes
+
+
+
+
+
+
+
+
+
+
+'The following GUID is for the ID of the typelib if this project is exposed to COM
+
+
+' Version information for an assembly consists of the following four values:
+'
+' Major Version
+' Minor Version
+' Build Number
+' Revision
+'
+' You can specify all the values or you can default the Build and Revision Numbers
+' by using the '*' as shown below:
+'
+
+
+
diff --git a/LockChecker/My Project/Resources.Designer.vb b/LockChecker/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..b8f458c
--- /dev/null
+++ b/LockChecker/My Project/Resources.Designer.vb
@@ -0,0 +1,62 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My.Resources
+
+ 'This class was auto-generated by the StronglyTypedResourceBuilder
+ 'class via a tool like ResGen or Visual Studio.
+ 'To add or remove a member, edit your .ResX file then rerun ResGen
+ 'with the /str option, or rebuild your VS project.
+ '''
+ ''' A strongly-typed resource class, for looking up localized strings, etc.
+ '''
+ _
+ Friend Module Resources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Returns the cached ResourceManager instance used by this class.
+ '''
+ _
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("LockChecker.Resources", GetType(Resources).Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Overrides the current thread's CurrentUICulture property for all
+ ''' resource lookups using this strongly typed resource class.
+ '''
+ _
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set(ByVal value As Global.System.Globalization.CultureInfo)
+ resourceCulture = value
+ End Set
+ End Property
+ End Module
+End Namespace
diff --git a/LockChecker/My Project/Resources.resx b/LockChecker/My Project/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/LockChecker/My Project/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/LockChecker/My Project/Settings.Designer.vb b/LockChecker/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..550a489
--- /dev/null
+++ b/LockChecker/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------
+'
+' This code was generated by a tool.
+' Runtime Version:4.0.30319.42000
+'
+' Changes to this file may cause incorrect behavior and will be lost if
+' the code is regenerated.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ _
+ Partial Friend NotInheritable Class MySettings
+ Inherits Global.System.Configuration.ApplicationSettingsBase
+
+ Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)
+
+#Region "My.Settings Auto-Save Functionality"
+#If _MyType = "WindowsForms" Then
+ Private Shared addedHandler As Boolean
+
+ Private Shared addedHandlerLockObject As New Object
+
+ _
+ Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
+ If My.Application.SaveMySettingsOnExit Then
+ My.Settings.Save()
+ End If
+ End Sub
+#End If
+#End Region
+
+ Public Shared ReadOnly Property [Default]() As MySettings
+ Get
+
+#If _MyType = "WindowsForms" Then
+ If Not addedHandler Then
+ SyncLock addedHandlerLockObject
+ If Not addedHandler Then
+ AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
+ addedHandler = True
+ End If
+ End SyncLock
+ End If
+#End If
+ Return defaultInstance
+ End Get
+ End Property
+ End Class
+End Namespace
+
+Namespace My
+
+ _
+ Friend Module MySettingsProperty
+
+ _
+ Friend ReadOnly Property Settings() As Global.LockChecker.My.MySettings
+ Get
+ Return Global.LockChecker.My.MySettings.Default
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/LockChecker/My Project/Settings.settings b/LockChecker/My Project/Settings.settings
new file mode 100644
index 0000000..85b890b
--- /dev/null
+++ b/LockChecker/My Project/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/RDP2MSILib/RDP2MSILib.vb b/RDP2MSILib/RDP2MSILib.vb
index d026bd7..408033d 100644
--- a/RDP2MSILib/RDP2MSILib.vb
+++ b/RDP2MSILib/RDP2MSILib.vb
@@ -1,5 +1,5 @@
Imports System.Reflection.Assembly
-
+Imports System.Windows.Forms
Public Class RDP
Private rdpFilePath As String
@@ -67,16 +67,45 @@ Public Class RDP
'Define temp files to delete
Dim FilesToDelete As List(Of String) = New List(Of String)(New String() {wxsPath, wixobjPath, wixpdbPath})
-
+ Dim LockCheck As New LockChecker.LockChecker()
+ Dim FileLocked As String
+ Dim SkipFile As Boolean = False
'Check if rdp file is already in TEMP folder
If rdpParentFolder = TempPath Then rdpInTemp = True
'if RDP file not in temp, copy to temp
If Not rdpInTemp Then
- My.Computer.FileSystem.CopyFile(rdpFilePath, rdpTempPath, True)
+ FileLocked = LockCheck.CheckLock(rdpTempPath)
+ While Not (FileLocked = "No locks")
+ If (MessageBox.Show("The file " + rdpTempPath + " is currently locked. Lock information:" + FileLocked + vbNewLine + "Do you want to try again?", "File Locked", MessageBoxButtons.YesNo) = DialogResult.Yes) Then
+ FileLocked = LockCheck.CheckLock(rdpTempPath)
+ Else
+ MessageBox.Show("The following file will not be deleted:" + vbNewLine + rdpTempPath)
+ SkipFile = True
+ FileLocked = "No locks"
+ End If
+ End While
+ If Not (SkipFile) Then
+ My.Computer.FileSystem.CopyFile(rdpFilePath, rdpTempPath, True)
+ End If
+
FilesToDelete.Add(rdpTempPath)
If hasIcon Then
- My.Computer.FileSystem.CopyFile(IconFilePath, icoTempPath, True)
+ FileLocked = LockCheck.CheckLock(icoTempPath)
+ While Not (FileLocked = "No locks")
+ If (MessageBox.Show("The file " + icoTempPath + " is currently locked. Lock information:" + FileLocked + vbNewLine + "Do you want to try again?", "File Locked", MessageBoxButtons.YesNo) = DialogResult.Yes) Then
+ FileLocked = LockCheck.CheckLock(icoTempPath)
+ Else
+ MessageBox.Show("The following file will not be deleted:" + vbNewLine + icoTempPath)
+ SkipFile = True
+ FileLocked = "No locks"
+ End If
+ End While
+ If Not (SkipFile) Then
+
+ My.Computer.FileSystem.CopyFile(IconFilePath, icoTempPath, True)
+ End If
+
FilesToDelete.Add(icoTempPath)
End If
@@ -95,7 +124,21 @@ Public Class RDP
'If Not LightExitCode = 0 Then Exit Sub
'Move MSI file to destination and delete temp files
- My.Computer.FileSystem.MoveFile(msiPath, DestinationPath, True)
+ FileLocked = LockCheck.CheckLock(DestinationPath)
+ While Not (FileLocked = "No locks")
+ If (MessageBox.Show("The file " + DestinationPath + " is currently locked. Lock information:" + FileLocked + vbNewLine + "Do you want to try again?", "File Locked", MessageBoxButtons.YesNo) = DialogResult.Yes) Then
+ FileLocked = LockCheck.CheckLock(DestinationPath)
+ Else
+ MessageBox.Show("The following file will not be deleted:" + vbNewLine + DestinationPath)
+ SkipFile = True
+ FileLocked = "No locks"
+ End If
+ End While
+ If Not (SkipFile) Then
+
+ My.Computer.FileSystem.MoveFile(msiPath, DestinationPath, True)
+ End If
+
DeleteFiles(FilesToDelete)
End Sub
@@ -122,7 +165,22 @@ Public Class RDP
Private Sub DeleteFiles(FilesArray As List(Of String))
For Each dFile In FilesArray
- If My.Computer.FileSystem.FileExists(dFile) Then My.Computer.FileSystem.DeleteFile(dFile)
+ Dim LockCheck As New LockChecker.LockChecker()
+ Dim FileLocked As String
+ Dim SkipFile As Boolean = False
+ FileLocked = LockCheck.CheckLock(dFile)
+ While Not (FileLocked = "No locks")
+ If (MessageBox.Show("The file " + dFile + " is currently locked. Lock information:" + FileLocked + vbNewLine + "Do you want to try again?", "File Locked", MessageBoxButtons.YesNo) = DialogResult.Yes) Then
+ FileLocked = LockCheck.CheckLock(dFile)
+ Else
+ MessageBox.Show("The following file will not be deleted:" + vbNewLine + dFile)
+ SkipFile = True
+ FileLocked = "No locks"
+ End If
+ End While
+ If Not (SkipFile) Then
+ If My.Computer.FileSystem.FileExists(dFile) Then My.Computer.FileSystem.DeleteFile(dFile)
+ End If
Next
End Sub
diff --git a/RDP2MSILib/RDP2MSILib.vbproj b/RDP2MSILib/RDP2MSILib.vbproj
index 0ed5219..c5a0025 100644
--- a/RDP2MSILib/RDP2MSILib.vbproj
+++ b/RDP2MSILib/RDP2MSILib.vbproj
@@ -46,6 +46,7 @@
+
@@ -99,6 +100,12 @@
Settings.Designer.vb
+
+
+ {029c010d-728b-4b87-b54a-08b2bbf49bd7}
+ LockChecker
+
+