I have an install widget the basically checks the ProductCode of an .msi, checks the registry to see if the product is installed, if not, it monitors msiexec processes and will fire the checked installer when the parent install process has finished.
When I watch this runnning with Task Manager, it seems that it is eating a ton of the CPU.
Is there any glaring memory leak in the following code? I'm no expert, and just know enough to get by so any tips would be appreciated...
Code:
Imports Microsoft.Win32
Imports System.Diagnostics
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.Close()
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim strFlag As String = Environment.GetCommandLineArgs.ElementAt(1) '0 element is path to .exe
Dim strCode As String
If strFlag = "/I" Then
Dim strPath As String = Environment.GetCommandLineArgs.ElementAt(2) '0 element is path to .exe
If Microsoft.VisualBasic.Right(strPath, 1) <> "\" Then
strPath = strPath & "\"
End If
'Get the Product Code and determine if installed...
strCode = GetProductCode(strPath & "Client\AdeptDWG\Install\RealDWGx64.msi")
If Not FindRelatedProduct(strCode) Then
'If not installed, no need to worry about removing earlier versions (different ProductCode) in code.
'Removal will be taken care of with Major Upgrade of new RealDWG installer.
'System.Threading.Thread.Sleep(30000)
Call CheckMSIExec()
Shell("msiexec /qb! /i """ & strPath & "Client\AdeptDWG\Install\RealDWGx64.msi""", AppWinStyle.NormalFocus, False)
End If
End
Else 'Uninstall RealDWG
Call RemoveRealDWG()
End
End If
End Sub
Public Function GetProductCode(ByVal msiFile As String) As String
Dim oInstaller As WindowsInstaller.Installer
Dim oDatabase As WindowsInstaller.Database
Dim oView As WindowsInstaller.View = Nothing
Dim oRecord As WindowsInstaller.Record
Dim strSQL As String
Dim strCode As String
Try
oInstaller = CType(CreateObject("WindowsInstaller.Installer"), WindowsInstaller.Installer)
oDatabase = oInstaller.OpenDatabase(msiFile, 0) 'Open Read-Only
strSQL = "SELECT * FROM `Property` WHERE `Property`='ProductCode'"
oView = oDatabase.OpenView(strSQL)
oView.Execute()
oRecord = oView.Fetch
strCode = oRecord.StringData(2)
Return strCode
Catch ex As Exception
'Do Nothing
MsgBox("[1]: " & ex.Message, MsgBoxStyle.OkOnly, "RealDWGx64 Product Code...")
End
Finally
oRecord = Nothing
If Not (oView Is Nothing) Then
oView.Close()
End If
oView = Nothing
oDatabase = Nothing
oInstaller = Nothing
End Try
End Function
Public Function FindRelatedProduct(ByVal strCode As String) As Boolean
Dim regKey As RegistryKey
Dim blnFound As Boolean = False
regKey = Registry.LocalMachine.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Uninstall")
For Each key In regKey.GetSubKeyNames
If key = strCode Then
blnFound = True
End If
Next
Return blnFound
End Function
Public Sub RemoveRealDWG()
Dim regKey, _
regKeySub As RegistryKey
Dim strValue As String
regKey = Registry.LocalMachine.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Uninstall")
For Each key In regKey.GetSubKeyNames
regKeySub = Registry.LocalMachine.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Uninstall\" & key)
strValue = regKeySub.GetValue("Comments")
If strValue = "RealDWG for x64 Adept Client" Then
'System.Threading.Thread.Sleep(30000)
Call CheckMSIExec()
Shell("msiexec /qb! /x " & key, AppWinStyle.NormalFocus, False)
End
End If
Next
End Sub
Public Sub CheckMSIExec()
'Cycle through running processes and see if MSI engine ready to start RealDWG installer...
Dim procList() As Process = Process.GetProcesses
Dim i As Integer
Dim intCount As Integer = 0
For i = 0 To procList.Count - 1
If InStr(UCase(procList(i).ProcessName), "MSIEXEC") > 0 Then
intCount = intCount + 1
End If
Next
If intCount > 1 Then
Call CheckMSIExec()
End If
End Sub
End Class
Everything works as I would like as coded, but there is a delay so something seems to have the need to be streamlined.
Again, any help is Greatly Appreciated!
Last edited by GremlinSA; July 10th, 2012 at 12:29 PM.
Reason: Added Code tags..
Public Sub CheckMSIExec()
'Cycle through running processes and see if MSI engine ready to start RealDWG installer...
Dim procList() As Process = Process.GetProcesses
Dim i As Integer
Dim intCount As Integer = 0
For i = 0 To procList.Count - 1
If InStr(UCase(procList(i).ProcessName), "MSIEXEC") > 0 Then
intCount = intCount + 1
End If
Next
If intCount > 1 Then
Call CheckMSIExec()
End If
End Sub
The highlighted code is your problem.. It recursively calls itself until 'MSIEXEC' is not running anymore.. There are no pauses in the code, and also every recursive call increases the stack, increasing memory usage...
The CheckMSIExec code was the problem. I changed that to a boolean function that returns True (still running) or false (OK to start other msi process).
I call this from a Do Until loop that contains a sleep for a second or two then a call to the function. It seems to have remedied the problem.
If there is an even better way to do it, please let me know. It's only a little widget run from an installer so I don't know how robust it has to/should be.
If there is an even better way to do it, please let me know.
The best method is always according to personal preference, and no two Guru's will always agree on the same method..
The Ideal method would involve Worker thread's and some API calls, which some may call overkill... But for your level of knowledge, what you've done is fine, and it's easier for you to debug in future. Threading and API's are a bugger to debug if you've never been into the inner sanctum of a Processor..
Last edited by GremlinSA; July 12th, 2012 at 03:53 AM.
Reason: fixed grammer
Bookmarks