Solved

VB.Net 2008 Error in a program started by my VB.Net app while shutting down

Posted on 2010-09-18
25
535 Views
Last Modified: 2012-05-10
Hi,

I have an application that sits in the system tray and calculates upload and download bandwidth to help us try and narrow down network slowdowns when they happen.

I was having a problem getting the app to exit neatly when the user logs off or shuts down so I've added this bit in:
--------------------------------------------------------------------------------------------
Const WM_ENDSESSION As Integer = &H11
    Dim osexit As Boolean = False

    Protected Overrides Sub WndProc(ByRef e As Message)
        If (e.Msg = WM_ENDSESSION) Then
            tmrMainProcess.Stop()
            Close()
            Application.Exit()
        End If
        MyBase.WndProc(e)
    End Sub
--------------------------------------------------------------------------------------------

Which is fine - and seems to work just fine... my current problem is that I get the data from netstat by running a process like this:
--------------------------------------------------------------------------------------------
objProcess.StartInfo.CreateNoWindow = True
objProcess.StartInfo.RedirectStandardOutput = True
objProcess.StartInfo.RedirectStandardError = True
objProcess.StartInfo.FileName() = "netstat"
objProcess.StartInfo.Arguments() = "-e"
objProcess.StartInfo.UseShellExecute = False
objProcess.Start()
NetStatData = objProcess.StandardOutput.ReadToEnd
NetStatDataError = objProcess.StandardError.ReadToEnd
objProcess.WaitForExit()
--------------------------------------------------------------------------------------------

Now during a logoff, I get an error from netstat (attached) saying that it failed to initialize... I'm guessing because the computer is shutting down.

Does anyone know how I can make this application close neatly? I want it to just close without a fuss!
The Error Message
0
Comment
Question by:spen_lang
  • 10
  • 8
  • 7
25 Comments
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33707810
How about closing the open netstate.exe before you close/exit your application. Use WM_QUERYENDSESSION instead of WM_ENDSESSION.
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33707888
Uhh my bad.. I see what your doing your actually repeat the same call openeing netstat process every time and wait for it to exit.. The error seems to indicate you tried to open netstat while dependancy files couldn't be loaded for it to work.
I would check to make sure that you don't attempt to spawn this process while or during the shutdown phase.. Your bit flag may need to be adjusted but theres not much code here to see the whole picture.
You also appear to be using WM_QUERYENDSESSION(&H11) constant value but you have it marked as WM_ENDSESSION(&H10) which is a different message so that was confusing.
 
0
 

Author Comment

by:spen_lang
ID: 33707905
Errr... I can attach the whole code if you like...
Imports System.IO

Imports System.Threading

Imports System.Math

Imports System.Data.OleDb

Imports System.Windows.Forms.NativeWindow



Public Class Form1



    Const WM_ENDSESSION As Integer = &H11

    Dim osexit As Boolean = False



    Protected Overrides Sub WndProc(ByRef e As Message)

        If (e.Msg = WM_ENDSESSION) Then

            osexit = True

            actuallyClose = True

            tmrMainProcess.Stop()

            Close()

            Application.Exit()

        End If

        MyBase.WndProc(e)

    End Sub





    Dim objProcess As New Process

    Dim NetStatData As String

    Dim NetStatDataError As String

    Dim SString As String()

    Dim DLoad As Long

    Dim ULoad As Long

    Dim ULoadAvg As Long

    Dim DLoadAvg As Long

    Dim LastULoad As Long = 0

    Dim LastDLoad As Long = 0

    Dim getLoadThread As Thread

    Dim graphicNumberDL As Integer = 0

    Dim graphicNumberUL As Integer = 0

    Dim doOnce As Boolean = True

    Public actuallyClose As Boolean = False

    Dim newPoint As New System.Drawing.Point()

    Dim a As Integer

    Dim b As Integer

    Dim count As Integer = 0



    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

        If actuallyClose = False Then

            e.Cancel = True

            Me.Hide()

            Me.Opacity = 0

            Form2.Hide()

            Form2.Opacity = 0

        Else

            tmrMainProcess.Stop()

            NotifyIcon1.Visible = False

        End If

    End Sub



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

        Form2.Label3.Text = "Started: " & Now

        Form2.Hide()

        Form2.Opacity = 1

        Me.Opacity = 0

        NotifyIcon1.Visible = True

        getLoadThread = New Thread(AddressOf GetLoadInfo)

        getLoadThread.Start()

        tmrMainProcess.Start()

        newPoint.X = My.Computer.Screen.WorkingArea.Width - Me.Width

        newPoint.Y = My.Computer.Screen.WorkingArea.Height - Me.Height

        Me.Location = newPoint

        NotifyIcon1.Icon = ImageToIcon(ImageList1.Images(0 & "-" & 0 & ".bmp"))

    End Sub



    Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown

        a = MousePosition.X - Me.Location.X

        b = MousePosition.Y - Me.Location.Y

    End Sub



    Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove

        If e.Button = MouseButtons.Left Then

            newPoint = MousePosition

            newPoint.X = newPoint.X - (a)

            newPoint.Y = newPoint.Y - (b)

            Me.Location = newPoint

            Form2.newPoint.X = Me.Location.X

            Form2.newPoint.Y = Me.Location.Y - (Me.Height - (Me.Height - Form2.Height))

            Form2.Location = Form2.newPoint

        End If

    End Sub



    Public Sub GetLoadInfo()

        Try

            objProcess.StartInfo.CreateNoWindow = True

            objProcess.StartInfo.RedirectStandardOutput = True

            objProcess.StartInfo.RedirectStandardError = True

            objProcess.StartInfo.FileName() = "netstat"

            objProcess.StartInfo.Arguments() = "-e"

            objProcess.StartInfo.UseShellExecute = False

            objProcess.Start()

            NetStatData = objProcess.StandardOutput.ReadToEnd

            NetStatDataError = objProcess.StandardError.ReadToEnd

            objProcess.WaitForExit()

            SString = Split(NetStatData, "Bytes")

            DLoad = (Int(Mid(SString(1), 14, 17)) / 3)

            ULoad = (Int(Mid(SString(1), 31, 16)) / 3)

            updateScreen()

        Catch ex As Exception

            MsgBox(ex.Message, MsgBoxStyle.Information, ex.InnerException)

        End Try

    End Sub



    Private Sub tmrMainProcess_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrMainProcess.Tick

        If osexit Then

            actuallyClose = True

            tmrMainProcess.Stop()

            Close()

        Else

            If doOnce = True Then

                Me.Hide()

                doOnce = False

            End If

            Call GetLoadInfo()

        End If

    End Sub



    Private Delegate Sub updateScreenDelegate()

    Public Sub updateScreen()

        If Me.InvokeRequired Then

            Dim upbd As New updateScreenDelegate(AddressOf updateScreen)

            Me.Invoke(upbd, New Object() {})

        Else

            graphicNumberDL = FormatNumber(((DLoad - LastDLoad) / 500000) * 10, 0)

            If graphicNumberDL < 0 Then

                graphicNumberDL = 0

            End If

            graphicNumberUL = FormatNumber(((ULoad - LastULoad) / 500000) * 10, 0)

            If graphicNumberUL < 0 Then

                graphicNumberUL = 0

            End If

            If doOnce = False Then

                If graphicNumberDL <= 10 Then

                    If graphicNumberUL <= 10 Then

                        NotifyIcon1.Icon = ImageToIcon(ImageList1.Images(graphicNumberDL & "-" & graphicNumberUL & ".bmp"))

                        Panel1.Width = graphicNumberDL * 10

                        Panel2.Width = graphicNumberUL * 10

                    Else

                        NotifyIcon1.Icon = ImageToIcon(ImageList1.Images(graphicNumberDL & "-" & 10 & ".bmp"))

                        Panel1.Width = graphicNumberDL * 10

                        Panel2.Width = 100

                    End If

                Else

                    If graphicNumberUL <= 10 Then

                        NotifyIcon1.Icon = ImageToIcon(ImageList1.Images(10 & "-" & graphicNumberUL & ".bmp"))

                        Panel1.Width = 100

                        Panel2.Width = graphicNumberUL * 10

                    Else

                        NotifyIcon1.Icon = ImageToIcon(ImageList1.Images(10 & "-" & 10 & ".bmp"))

                        Panel1.Width = 100

                        Panel2.Width = 100

                    End If

                End If

            End If

        If doOnce = False Then

            Try

                NotifyIcon1.Text = "Upload: " & roundBytes(ULoad - LastULoad) & "/s" & vbCrLf & "Download: " & roundBytes(DLoad - LastDLoad) & "/s"

            Catch ex As Exception

                    MsgBox(ex.Message, MsgBoxStyle.Information, ex.InnerException)

                End Try

                Try

                    lblDownload.Text = roundBytes(DLoad - LastDLoad) & "/s"

                    lblUpload.Text = roundBytes(ULoad - LastULoad) & "/s"

                Catch ex As Exception

                    MsgBox(ex.Message, MsgBoxStyle.Information, ex.InnerException)

                End Try

            End If

            If doOnce = False Then

                ULoadAvg = ULoadAvg + (ULoad - LastULoad)

                DLoadAvg = DLoadAvg + (DLoad - LastDLoad)

            End If

            LastDLoad = DLoad

            LastULoad = ULoad

            If doOnce = False Then

                Form2.Label1.Text = "Average DL Speed: " & roundBytes(FormatNumber((DLoadAvg / count), 0))

                Form2.Label2.Text = "Average UL Speed: " & roundBytes(FormatNumber((ULoadAvg / count), 0))

                count = count + 1

            End If

            End If

    End Sub



    Function roundBytes(ByVal bytes As String)

        If bytes > 1073741824 Then

            Return Round(bytes / 1073741824, 2) & " GB"

        ElseIf bytes > 1048576 Then

            Return Round(bytes / 1048576, 2) & " MB"

        ElseIf bytes > 1024 Then

            Return Round(bytes / 1024, 2) & " KB"

        ElseIf bytes = 0 Then

            Return bytes & " B"

        Else

            Return bytes & " B"

        End If

    End Function



    Public Declare Function DestroyIcon Lib "user32" (ByVal hIcon As IntPtr) As Integer

    Public Function ImageToIcon(ByVal image As System.Drawing.Image) As System.Drawing.Icon

        Dim bitmap As New System.Drawing.Bitmap(image)

        Dim UnmanagedIconHandle As IntPtr = bitmap.GetHicon()

        Dim myIcon As System.Drawing.Icon = TryCast(System.Drawing.Icon.FromHandle(UnmanagedIconHandle).Clone(), Icon)

        DestroyIcon(UnmanagedIconHandle)

        Return myIcon

    End Function



    Private Sub NotifyIcon1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles NotifyIcon1.MouseClick

        If ((Control.ModifierKeys And Keys.Control) = Keys.Control) And ((Control.ModifierKeys And Keys.Shift) = Keys.Shift) Then

            newPoint.X = My.Computer.Screen.WorkingArea.Width - Me.Width

            newPoint.Y = My.Computer.Screen.WorkingArea.Height - Me.Height

            Me.Location = newPoint

            Form2.newPoint.X = Me.Location.X

            Form2.newPoint.Y = Me.Location.Y - (Me.Height - (Me.Height - Form2.Height))

            Form2.Location = Form2.newPoint

            Me.Show()

            Me.Opacity = 1

        End If

    End Sub



    Private Sub btnHide_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHide.Click

        Close()

    End Sub



    Private Sub btnMore_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnMore.Click

        If Form2.Visible = True Then

            Form2.Hide()

            Form2.Opacity = 0

            btnMore.Text = "More"

        Else

            Form2.Show()

            Form2.Opacity = 1

            Form2.newPoint.X = Me.Location.X

            Form2.newPoint.Y = Me.Location.Y - (Me.Height - (Me.Height - Form2.Height))

            Form2.Location = Form2.newPoint

            btnMore.Text = "Less"

        End If

    End Sub



End Class

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33708084
LOL.. Well thats alot of code to digest.. =)
You don't need to exit your application in WndProc() you can avoid using WndProc() all together and handle all the cleanup in the FormClosing() event. Windows will send the message to all top level windows so your FormsClosing() event will be entered. Here you can add the appropriate logic to handle clean up and disable the timers. Overriding the WndProc() here is only useful if you want inform windows to not shutdown because there is unsaved document or burning in progress things like that..
I'll try to replicate your issue but for now I just suggest removing the WndProc() and handle this cleanup in FormClosing.

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

Select Case e.CloseReason

Case CloseReason.WindowsShutDown

Case CloseReason.UserClosing

End Select

End Sub

Open in new window

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 33708105
In WndProc() try KILLING netstat if it's still running:

    Protected Overrides Sub WndProc(ByRef e As Message)
        If (e.Msg = WM_ENDSESSION) Then
            osexit = True
            actuallyClose = True
            tmrMainProcess.Stop()

            If Not objProcess.HasExited Then
                objProcess.Kill()
            End If

            Close()
            Application.Exit()
        End If
        MyBase.WndProc(e)
    End Sub

Then, in GetLoadInfo(), make sure you don't attempt to process the output by checking the "actuallyClose" flag:

    Public Sub GetLoadInfo()
        Try
            objProcess.StartInfo.CreateNoWindow = True
            objProcess.StartInfo.RedirectStandardOutput = True
            objProcess.StartInfo.RedirectStandardError = True
            objProcess.StartInfo.FileName() = "netstat"
            objProcess.StartInfo.Arguments() = "-e"
            objProcess.StartInfo.UseShellExecute = False
            objProcess.Start()
            NetStatData = objProcess.StandardOutput.ReadToEnd
            NetStatDataError = objProcess.StandardError.ReadToEnd
            objProcess.WaitForExit()

            If Not actuallyClose Then
                SString = Split(NetStatData, "Bytes")
                DLoad = (Int(Mid(SString(1), 14, 17)) / 3)
                ULoad = (Int(Mid(SString(1), 31, 16)) / 3)
                updateScreen()
            End If
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Information, ex.InnerException)
        End Try
    End Sub

*Finally, why go thru the effort of making GetLoadInfo() threaded?

        getLoadThread = New Thread(AddressOf GetLoadInfo)
        getLoadThread.Start()

When you later simply run it over and over from the main UI thread via the Tick() event of your Timer?

    Private Sub tmrMainProcess_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrMainProcess.Tick
        If osexit Then
            actuallyClose = True
            tmrMainProcess.Stop()
            Close()
        Else
            If doOnce = True Then
                Me.Hide()
                doOnce = False
            End If
            Call GetLoadInfo()  ' <---------------- This will run GetLoadInfo() in the main UI thread!
        End If
    End Sub
0
 

Author Comment

by:spen_lang
ID: 33708162
@egl1044: I was clearing everything up in the closing event, but I was trying to get it to stop doing everything immediatly on the logoff message...

@Idle_Mind: I've tried that and I still get the error from netstat :(

I'm running a seperate thread for the GetLoadInfo() sub because the app would hang momentarily on each tick - that fied it :)


Still stuck - I can't deploy this to our users unless this problem goes away... and that makes me sad!

There must be a way of getting this app to close neatly?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 33708178
"I'm running a seperate thread for the GetLoadInfo() sub because the app would hang momentarily on each tick - that fied it :)"

Only the FIRST run of GetLoadInfo() that is launched from the Load() event is actually threaded.

ALL subsequent calls from your Tick() event are NOT threaded...this is what I was pointing out.  =\

You would need to create a new thread in each Tick() event or simply make the Thread have a While True loop and make it Sleep() for the desired Interval.  This would eliminate the Timer completely.
0
 

Author Comment

by:spen_lang
ID: 33708207
Ah - I see! Well I will sort that out then - I wasn't aware of my mistake - thanks.

On the other note though... any thoughts?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 33708247
What is your Timer Interval set at?
0
 

Author Comment

by:spen_lang
ID: 33708256
1000
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 33708271
I'm having trouble making the error popup on my system (Win 7 Pro 64-bit).

Here's my boiled down test code:
Public Class Form1



    Private T As System.Threading.Thread



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

        T = New System.Threading.Thread(AddressOf NetStat)

        T.IsBackground = True

        T.Start()

    End Sub



    Private Sub NetStat()

        While True

            Dim NetStatData As String

            Dim NetStatDataError As String

            Dim SString() As String

            Dim DLoad As Long

            Dim ULoad As Long



            Dim objProcess As New Process

            objProcess.StartInfo.CreateNoWindow = True

            objProcess.StartInfo.RedirectStandardOutput = True

            objProcess.StartInfo.RedirectStandardError = True

            objProcess.StartInfo.FileName() = "netstat"

            objProcess.StartInfo.Arguments() = "-e"

            objProcess.StartInfo.UseShellExecute = False

            objProcess.Start()

            NetStatData = objProcess.StandardOutput.ReadToEnd

            NetStatDataError = objProcess.StandardError.ReadToEnd

            objProcess.WaitForExit()



            SString = Split(NetStatData, "Bytes")

            DLoad = (Int(Mid(SString(1), 14, 17)) / 3)

            ULoad = (Int(Mid(SString(1), 31, 16)) / 3)

            UpdateData(DLoad, ULoad)



            System.Threading.Thread.Sleep(1000)

        End While

    End Sub



    Private Delegate Sub UpdateDataDelegate(ByVal DLoad As Long, ByVal ULoad As Long)



    Private Sub UpdateData(ByVal DLoad As Long, ByVal ULoad As Long)

        If Me.InvokeRequired Then

            Me.Invoke(New UpdateDataDelegate(AddressOf UpdateData), New Object() {DLoad, ULoad})

        Else

            Label1.Text = "DLoad = " & DLoad

            Label2.Text = "ULoad = " & ULoad

        End If

    End Sub



End Class

Open in new window

0
 

Author Comment

by:spen_lang
ID: 33708314
I'm on XP x86 - I can't attach the project cause EE won't allow ico files!

So here's the link to the project: http://www.langdons.co.uk/barGraphThing.zip
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 33708321
To upload to EE, try adding a fake extension to your zip file...something like "barGraphThing.zip.txt".
0
 

Author Comment

by:spen_lang
ID: 33708330
I tried that... it worked out what i'd done! I've put the file on the website for you to collect.
0
 
LVL 29

Accepted Solution

by:
nffvrxqgrcfqvvc earned 500 total points
ID: 33711328
I had some time to play with the code, I thought that the framework might have this information available already so I looked into the object browser and found that the NetworkInterface Class has tons of information about the network devices..
You might be able to get the information your looking for using the .NET class directly!
Here is an example that shows bytesSent and BytesRecieved for each interface. You may have to look deeper for specific information you need for your application but it most certainly looks like everything is available in this class.

Dim netInterface As NetworkInterface() = NetworkInterface.GetAllNetworkInterfaces

For Each net As NetworkInterface In netInterface

Dim statistics As IPv4InterfaceStatistics = net.GetIPv4Statistics

Debug.Print("Name:{0} Type:{1}", net.Name, net.NetworkInterfaceType)

Debug.Print("Rec:{0} Sent:{1}", statistics.BytesReceived, statistics.BytesSent)

Next

Open in new window

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 33711521
You rock egl1044!  Love reading your posts...   =)
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33711588
Thanks Idle_Mind I also enjoy reading your posts just as much! You always give good information and never really just post (links) as many people often do in questions. You share your knowledge and understanding of problems on each subject and I admire that!
0
 

Author Closing Comment

by:spen_lang
ID: 33715896
Hi,

Thanks for all your help - I think this will fix the problem... it doesn't really find a cure for opening other programs repeatedly and then logging off, but for this application, I can use this fix.

Thank you
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33717182
You have an alternative to your code that is much better than opening the netstat process in a loop. You should be more than excited to find an alternative to opening a process every second then parsing the redirection! Each time you do this the framework has to open pipe handles every time, every second, surely not very robust compared to using PURE .NET methods that most likely talk to the device directly.
<< it doesn't really find a cure for opening other programs repeatedly and then logging off >>
Idle_Mind already provided you an example http:#33708271 that fixed many of the problems in your original code.
0
 

Author Comment

by:spen_lang
ID: 33717719
I didn't mean it like that... there should be a sarcasm font!

I should have added the statement "so I'm happy!"


I'm sorry if that sounded off - I wasn't really paying full attention.

Thank you for all your help - I really appreciate your comments and suggestions, and I am much happier using true .NET... and I'm also pleased that other little things have been fixed - like the pointless re-threading.

Please don't hate me!
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33717804
I don't hate you, I just wanted to see if I could figure out the justification of warranting a "B" grade when the new approach is a MUCH better alternative to your problem. The problem really could be with your computer and nothing else it's hard to figure out why you get the error in your original code but Idle_Mind cleaned it up so that it "should" work if you still wanted to take that approach which should have been awarded something because it tackles your original question.
The "B" grade triggered (You should be more than excited) because the grade means you really didn't feel the solution was better and I wanted to ensure you understood why it was better. =)
0
 

Author Comment

by:spen_lang
ID: 33717881
Oh... I usually save the A grade answers for when I'm absolutely wowed and am in awe of something!

Like Murray Walker used to say - always leave room to go another octive!

I don't know how to change it to an A now? sorry - absolutely no offence meant with that, I thuoght I was doing the right thing...
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 33718053
ohh jesus your right..  You throw out enough B's to make honey.  I understand you have a personal way of grading and I can respect that just wanted to explain why it was better in case you didn't understand. =)
0
 

Author Comment

by:spen_lang
ID: 33718429
Cool :)

I hope our paths cross again... and I hope we're cool :)
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 33719031
Lol...funny ending to the thread there...glad you found a solution you're happy with!  =D
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Don’t let your business fall victim to the coming apocalypse – use our Survival Guide for the Fax Apocalypse to identify the risks and signs of zombie fax activities at your business.
For both online and offline retail, the cross-channel business is the most recent pattern in the B2C trade space.
Viewers will learn how to connect to a wireless network using the network security key. They will also learn how to access the IP address and DNS server for connections that must be done manually. After setting up a router, find the network security…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now