borderAndreaVB free resources for Visual Basic developersborder

borderAndreaVB Visual Basic and VB.NET source code resources - Copyright © 1999-2007 Andrea Tincaniborder

AndreaVB | Forum | News | Downloads | Register | Help | Member List | Statistics | Search | PM | Profile

Print This Topic
Previous Topic (Hi need help packet sender)Next Topic (Retrieving values from .INC file) New Topic New Poll Post Reply
AndreaVB Forum : Internet Applications : Need help : Ping function called in a thread
Poster Message
Mig
Level: Guest


icon Need help : Ping function called in a thread

Hi!
I'm starting with VB6 and i have some problems with my internet service provider.  I constantly loose access to the internet and I want to proove them.  I want to create an application who ping's constantly some websites to discover when i loose my internet service and when i regain it.  After all, i want to log it all in a file.

I used a commandButton to start the application and another one to stop it.  I must use a thread to ping 3 different websites at each minute without loosing the control on my application.

There is the problem!

First of all, the following code is in a module called "modPing.bas".  
-----------------------------------------------------------------------
Option Explicit
Private Const SOCKET_ERROR = 0
Private Const MAX_IP = 10

'**********************************
'Déclaration des types de données *
'**********************************
Private Type WSAdata
    wVersion As Integer
    wHighVersion As Integer
    szDescription(0 To 255) As Byte
    szSystemStatus(0 To 128) As Byte
    iMaxSockets As Integer
    iMaxUdpDg As Integer
    lpVendorInfo As Long
End Type

Private Type Hostent
    h_name As Long
    h_aliases As Long
    h_addrtype As Integer
    h_length As Integer
    h_addr_list As Long
End Type

Private Type IP_OPTION_INFORMATION
    TTL As Byte
    Tos As Byte
    Flags As Byte
    OptionsSize As Long
    OptionsData As String * 128
End Type

Private Type IP_ECHO_REPLY
    Address(0 To 3) As Byte
    Status As Long
    RoundTripTime As Long
    DataSize As Integer
    Reserved As Integer
    data As Long
    Options As IP_OPTION_INFORMATION
End Type

'***************************
'Déclaration des fonctions *
'***************************
Private Declare Function GetHostByName Lib "wsock32.dll" Alias "gethostbyname" (ByVal HostName As String) As Long
Private Declare Function WSAStartup Lib "wsock32.dll" (ByVal wVersionRequired&, lpWSAdata As WSAdata) As Long
Private Declare Function WSACleanup Lib "wsock32.dll" () As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)
Private Declare Function IcmpCreateFile Lib "icmp.dll" () As Long
Private Declare Function IcmpCloseHandle Lib "icmp.dll" (ByVal HANDLE As Long) As Boolean
Private Declare Function IcmpSendEcho Lib "ICMP" (ByVal IcmpHandle As Long, ByVal DestAddress As Long, ByVal RequestData As String, ByVal RequestSize As Integer, RequestOptns As IP_OPTION_INFORMATION, ReplyBuffer As IP_ECHO_REPLY, ByVal ReplySize As Long, ByVal Timeout As Long) As Boolean

'*****************************************
'Fait un ping au site passé en paramêtre *
'*****************************************
Public Function Ping(sAddr As String, Optional Timeout As Integer = 2000) As Integer
    Dim hFile As Long, lpWSAdata As WSAdata
    Dim hHostent As Hostent, AddrList As Long
    Dim Address As Long, rIP As String
    Dim OptInfo As IP_OPTION_INFORMATION
    Dim EchoReply As IP_ECHO_REPLY
    
    Call WSAStartup(&H101, lpWSAdata)
    
    If GetHostByName(sAddr + String(64 - Len(sAddr), 0)) <> SOCKET_ERROR Then
        CopyMemory hHostent.h_name, ByVal GetHostByName(sAddr + String(64 - Len(sAddr), 0)), Len(hHostent)
        CopyMemory AddrList, ByVal hHostent.h_addr_list, 4
        CopyMemory Address, ByVal AddrList, 4
    End If
    
    hFile = IcmpCreateFile()
    
    If hFile = 0 Then
        Ping = -2 ' MsgBox "Unable to Create File Handle"
        Exit Function
    End If
    
    OptInfo.TTL = 255
    
    If IcmpSendEcho(hFile, Address, String(32, "A"), 32, OptInfo, EchoReply, Len(EchoReply) + 8, Timeout) Then
        rIP = CStr(EchoReply.Address(0)) + "." + CStr(EchoReply.Address(1)) + "." + CStr(EchoReply.Address(2)) + "." + CStr(EchoReply.Address(3))
    Else
        Ping = -1 ' MsgBox "Timeout"
    End If
    
    If EchoReply.Status = 0 Then
        Ping = EchoReply.RoundTripTime
    Else
        Ping = -3
    End If
    
    IcmpCloseHandle hFile
    WSACleanup

End Function

--------------------------------------------------------------------
In a different project (Ping.vbp), only a commandButton is needed to call the "ping" function with the following instructions in a "form". It works perfectly!!!

Private Sub Command1_Click()
    Dim Result As Integer
    
    Result = modPing.Ping("www.google.com")
    
    If Result < 0 Then
        MsgBox "Ping failed, error: " & Result
    Else
        MsgBox "Ping ok, Résultat: " & Result
    End If
End Sub

---------------------------------------------------------
In the contrary, I want to call this function at each minute in a thread until the stop commandButton is clicked or  the application is closed.  I added this module (modPing.bas) to another project  (NetUpDown.vbp).

There is the description of the "form" called "frmPrincipale" of the new project(NetUpDown.vbp).

1 textBox called "txtNetStatut"
1 textBox called "txtDateHre"
1 commandButton called "btnStart"
1 commandButton called "btnStop"
1 comboBox called "cmbLog"

In the "frmPrincipale" form, I added the following code :

-------------------------------------------------------------------

'************************************************************
'  Règles à respecter pour ce programme!                    *
'************************************************************
' 1) Do not run the vb thread application from debug.       *
'    Run the application as a compiled executable.          *
'    Instead compile and run the executable.                *
'                                                           *
'    Call TerminateProcess(GetCurrentProcess, ByVal 0&)     *
'    will terminate the current vb process                  *
'                                                           *
' 2) Test each function first before embedding into the     *
'    thread frame work application.                         *
'                                                           *
' 3) Make sure the project is compiled as P-Code            *
'    (executable will fault if the binary is not P-Code)    *
'************************************************************
'*****************************************************
' Déclaration des variables globales
'*****************************************************
Public blnFichEcrit As Boolean

'*******************************************************
'Commandes exécutées lorsque le bouton Start est cliqué
'*******************************************************
Private Sub btnStart_Click()

    Dim lpThreadID As Long
    Dim strNomFich As String
    
    blnFichEcrit = False
    
    'Créer le Thread et l'événement pour ne créer qu'un seul thread
    lThreadHandle1 = CreateThread(ByVal 0&, ByVal 0&, AddressOf VerifNet, ByVal 0&, 0, lpThreadID)
    
    lEventHandle = CreateEvent(ByVal 0&, False, False, ByVal 0&)

    'Désactiver le bouton Start
    frmPrincipale.btnStart.Enabled = False
    frmPrincipale.btnStop.Enabled = True
    
End Sub

'*******************************************************
'Commandes exécutées lorsque le bouton Stop est cliqué
'Fin normale
'*******************************************************
Private Sub btnStop_Click()
    Dim lRC As Long

    'Crée un événement.  Le Thread vérifie sa présence pour se terminer correctement
    lRC = SetEvent(lEventHandle)

    'Une fois que le thread s'est arrèté correctement on le kill
    If lThreadHandle1 > 0 Then
        Call TerminateThread(lThreadHandle1, ByVal 0&)
    End If

    lThreadHandle1 = 0

    'Activer le bouton Start
    frmPrincipale.btnStart.Enabled = True
    frmPrincipale.btnStop.Enabled = False
    
    
    If blnFichEcrit = False Then
        blnFichEcrit = True
        EcrireLog
    End If
    
End Sub

'********************************************************
' Module exécuté lorsque la fenêtre se ferme avec le "X"
' Fin forcée
'********************************************************
Private Sub Form_Unload(Cancel As Integer)

    If lThreadHandle1 > 0 Then
        Call TerminateThread(lThreadHandle1, ByVal 0&)
    End If
  
    If blnFichEcrit = False Then
        blnFichEcrit = True
        EcrireLog
    End If
    
    Call TerminateProcess(GetCurrentProcess, ByVal 0&)

End Sub

'*****************************************************
' Permet d'écrire une ligne de données du fichier log
'******************************************************
Public Sub EcrireLog()
    Dim strNomFich As String

    'Ouverture du fichier
    strNomFich = "C:\Documents and Settings\Mig1\Mes documents\Projets VB\NetUpDown\LogNetUpDown.txt"
    Open strNomFich For Append As #1

    EcrireEttLog

    'Écrit tous les éléments de la Combo Box
    For i = 0 To cmbLog.ListCount
        Write #1, "" & cmbLog.List(i)
    Next i
    
    'Vide la ComboBox
    cmbLog.Clear
    
    'Ferme le fichier.
    Close #1

End Sub

'*****************************************************
' Permet d'écrire les lignes d'entête du fichier log
'******************************************************
Public Sub EcrireEttLog()
    
    Write #1, "--------------------------------------------"
    Write #1, "Statut d'internet + Date et heure du système"
    Write #1, "--------------------------------------------"
    Write #1,   ' Écrit une ligne vierge.
    
End Sub

--------------------------------------------------------------------

There is the code added in the module called "modNetUpDown.bas" :

-------------------------------------------------------------------
'************************************************************
'  Règles à respecter lors de l'utilisation de thread       *
'************************************************************
' 1) La déclaration des fonctions doit se faire dans un     *
'    module.  Elles doivent être publiques.                 *
'                                                           *
' 2) Toute fonction appelée avec, en paramêtre, AddressOf   *
'    doit être définie dans un module.                      *
'************************************************************

Option Explicit
'******************************************************************************************************
'I tried this function but must search for another function because this one does not work correctly.
'It returns true when :
'   - the power plug of my external modem is put in
'   - the power plug of my external modem is take out
'It only returns false when :
'   - I force my firewall to block the internet access to this application
'******************************************************************************************************
'PING
'Private Declare Function InternetCheckConnection Lib "wininet.dll" _
'    Alias "InternetCheckConnectionA" _
'    (ByVal lpszUrl As String, ByVal dwFlags As Long, ByVal dwReserved As Long) As Long
        
'Crée un Thread
Public Declare Function CreateThread Lib "kernel32" _
    (ByVal lpThreadAttributes As Any, ByVal dwStackSize As Long, _
     ByVal lpStartAddress As Long, lpParameter As Any, _
     ByVal dwCreationFlags As Long, lpThreadID As Long) As Long
    
'WAIT
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
    ' Sleep 1 seconde
        ' Sleep 1000
    ' Sleep 5 secondes
        ' Sleep 5000
    
'Termine un Thread
Public Declare Function TerminateThread Lib "kernel32" _
    (ByVal hThread As Long, ByVal dwExitCode As Long) As Long

'Termine un processus
Public Declare Function TerminateProcess Lib "kernel32" _
    (ByVal hProcess As Long, ByVal uExitCode As Long) As Long

'Obtient le processus courrant
Public Declare Function GetCurrentProcess Lib "kernel32" () As Long

'Attente d'un signal
Public Declare Function WaitForSingleObject Lib "kernel32.dll" _
    (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    
'Crée un événement
Public Declare Function CreateEvent& Lib "kernel32" _
    Alias "CreateEventA" _
    (ByVal lpEventAttributes As Long, _
     ByVal bManualReset As Long, ByVal bInitialState As Long, _
     ByVal lpname As String)

'Affecte un événement
Public Declare Function SetEvent Lib "kernel32" (ByVal hEvent As Long) As Long

'*****************************************************
' Déclaration des variables globales
'*****************************************************
Public lThreadHandle1 As Long
Public lEventHandle As Long

'*****************************************************
' Module exécuté lorsque la fenêtre est chargée
'*****************************************************
Public Sub Main()

    frmPrincipale.Show

End Sub

'*****************************************************
' Module du traitement principal
' Traitement du thread
'*****************************************************
Public Sub VerifNet()
    
    Dim lretCod         As Long
    Dim blnAllPingOK    As Boolean
    Dim blnOldStatusUp  As Boolean
    Dim strNetStatus    As String
    Dim intIndex        As Integer
                  
    intIndex = 0
                      
    'Déterminer si le net est up
    blnAllPingOK = PingAllSite
    If blnAllPingOK Then
        blnOldStatusUp = True
        strNetStatus = "UP  "
    Else
        blnOldStatusUp = False
        strNetStatus = "DOWN"
    End If

    'On inscrit le statut de départ
    Call InscrireLog(intIndex, strNetStatus)
    
    'Répétition du traitement jusqu'a ce que le bouton "Stop soit cliqué"
    Do
        'Attendre 30 secondes (30000 millisecondes) avant de refaire la vérification
        Sleep (30000)
        
        'Déterminer si le net est up
        blnAllPingOK = PingAllSite
        'Si le statut change, on inscrit au log
        If blnAllPingOK Then
            If blnOldStatusUp = False Then
               blnOldStatusUp = True
               strNetStatus = "UP  "
               Call InscrireLog(intIndex, strNetStatus)
            End If
        Else
            If blnOldStatusUp Then
               blnOldStatusUp = False
               strNetStatus = "DOWN"
               Call InscrireLog(intIndex, strNetStatus)
            End If
        End If
        
        DoEvents
        'Vérifie aux 5 secondes si le bouton "STOP" a créé un événement pour que le thread s'arrète normalement
        lretCod = WaitForSingleObject(lEventHandle, 5000)
    
     Loop Until lretCod = 0
    
End Sub

'*****************************************************************
'Fait un PING à 3 sites.  Si au moins une réponse, le net est UP
'*****************************************************************
Public Function PingAllSite() As Boolean

    Dim intRepSite1 As Integer
    Dim intRepSite2 As Integer
    Dim intRepSite3 As Integer

    'Faire un "PING" à 3 sites différents
    intRepSite1 = ModPing.Ping("www.videotron.com")
    intRepSite2 = ModPing.Ping("www.microsoft.com")
    intRepSite3 = ModPing.Ping("www.google.com")

    'Si un des 3 sites répond, le net est "UP"
    If intRepSite1 >= 0 Or intRepSite2 >= 0 Or intRepSite3 >= 0 Then
       PingAllSite = True
    Else
       PingAllSite = False
    End If

End Function

'*****************************************************************
'Inscrire une ligne au log (cumulet les infos dans une ComboBox
'*****************************************************************
Public Sub InscrireLog(ByRef intIdx As Integer, ByVal strStatus As String)
    Dim strDatHre As String
    Dim strItem As String
    
    'Obtenir la date et l'heure du système
    strDatHre = "" & Now
    'Afficher le nouveau statut et la date/heure
    frmPrincipale.txtNetStatut.Text = strStatus
    frmPrincipale.txtDateHre.Text = strDatHre
    'Ajouter un record à écrire au log
    intIdx = intIdx + 1
    strItem = "" & strStatus & " - " & strDatHre & intIdx
    frmPrincipale.cmbLog.AddItem strItem

End Sub

----------------------------------------------------------------
The error appears when the function "GetHostByName" is called by the function "Ping" in the module "modPing.bas".  I don't understant why this code doesn't work when it's call in a thread   It works correctly in the last project (Ping.vbp)!!!
It says : "L'instruction à "0x660fea4f" emploie l'adresse mémoire "0x00000050".  La mémoire ne peut pas être "read".
English translation : The instruction at "0x660fea4f" use the memory address "0x00000050".  The memory cannot be read.

Did i do someting wrong?!  I don't understant what?
Do threads have particularities or special constraints

thank you very much!

14-10-2004 at 01:54 AM
| Quote Reply
AndreaVB Forum : Internet Applications : Need help : Ping function called in a thread
Previous Topic (Hi need help packet sender)Next Topic (Retrieving values from .INC file) New Topic New Poll Post Reply
Surf To:


Not Logged In? Username: Password: Lost your password?
Partners: Download Actual Software | Free Software Download
borderAndreaVB free resources for Visual Basic developersborder

borderAndreaVB Visual Basic and VB.NET source code resources - Copyright © 1999-2007 Andrea Tincaniborder