Windows platform - network diagnostic app

Just starting out? Need help? Post your questions and find answers here.
lesserpanda
User
User
Posts: 65
Joined: Tue Feb 11, 2020 7:50 am

Windows platform - network diagnostic app

Post by lesserpanda »

Looking to build a tool which

1. Ping and save ms to certain list of IPs.
2. Measure jitter ms

Any network library or dll I can hook into that anyone knows of?

Just wanting some diagnostic data and thought it might be something which I can use to learn more PB!

Thanks!
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Windows platform - network diagnostic app

Post by jassing »

This help?

Code: Select all

; Author: TerryHough (modified by celtic88)

DeclareModule pi
  Declare ng(Address.s,PING_TIMEOUT=1000,strMessage.s = "Echo This Information Back To Me")
EndDeclareModule
Module pi
  Global Ping_Port = IcmpCreateFile_() 
  
  Procedure.q lngNewAddress(strAdd.s) 
    Protected sDummy.s=strAdd 
    Protected Position = FindString(sDummy, ".",1) 
    If Position>0 
      Protected a1=Val(Left(sDummy,Position-1)) 
      sDummy=Right(sDummy,Len(sDummy)-Position) 
      Position = FindString(sDummy, ".",1) 
      If Position>0 
        Protected A2=Val(Left(sDummy,Position-1)) 
        sDummy=Right(sDummy,Len(sDummy)-Position) 
        Position = FindString(sDummy, ".",1) 
        If Position>0 
          Protected A3=Val(Left(sDummy,Position-1)) 
          sDummy=Right(sDummy,Len(sDummy)-Position) 
          Protected A4=Val(sDummy) 
          Protected dummy.q=0 
          PokeB(@dummy,a1) 
          PokeB(@dummy+1,A2) 
          PokeB(@dummy+2,A3) 
          PokeB(@dummy+3,A4) 
          ProcedureReturn dummy 
        EndIf 
      EndIf 
    EndIf 
  EndProcedure 
  
  Procedure ng(Address.s,PING_TIMEOUT=1000,strMessage.s = "Echo This Information Back To Me")
    If Ping_Port
      Protected MsgLen = Len(strMessage) 
      Protected ECHO.ICMP_ECHO_REPLY 
      Protected IPAddressNumber.q = lngNewAddress(Address.s)
      Protected *buffer=AllocateMemory(SizeOf(ICMP_ECHO_REPLY)+MsgLen) 
      Protected lngResult = IcmpSendEcho_(Ping_Port, IPAddressNumber, @strMessage, MsgLen , #Null,*buffer, SizeOf(ICMP_ECHO_REPLY)+MsgLen,PING_TIMEOUT) 
      If lngResult
        CopyMemory(*buffer,@ECHO,SizeOf(ICMP_ECHO_REPLY)) 
      EndIf
      FreeMemory(*buffer)
      If lngResult
        ProcedureReturn ECHO\RoundTripTime
      Else
        ProcedureReturn -1
      EndIf
    EndIf
  EndProcedure
EndModule

Debug Pi::ng("74.125.136.188")
User avatar
Michael Vogel
Addict
Addict
Posts: 2797
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Windows platform - network diagnostic app

Post by Michael Vogel »

Hi, maybe also a starter, did write the following more than ten years ago...

...so it's far from perfect - and the program need's a very specific preference file, here's an example which includes a default set (*) and another set (Academy) of devices. To choose a set you'd have to start the program while keeping pressed the shift key.

I know the program is confusing (I did write the program "offline" while on a train) but maybe the ICMP and SNMP parts can be interesting.

Code: Select all

;[VPing Konfiguration]
;S=16	window size (8..32)
;H=20	header size (8..32)
;M=0	shrink font (0..32)
;N=5	shrink header (0..32)
;W=14	enlarge window width (0..32)
;Z=4	line gap (0..10)
;I=250	ping intervall (ms)
;T=200	Ping timeout (ms)
;P=0	Packet size (-Data / +Total Bytes)
;D=0	History (0:off / 1:dots)
;F=0	indicators (0:fix / 1:off)
;V=1	video buffer (0 / 1:no flicker)
;B=2	bar color (0:off / 1:light / 2:dark)
;O=0	On top (0:off / 1:on)
;U=0	Update DNS/local addresses (secs)
;G=0	Log file
;.=1	127.0.0.1 (0:off / 1:on, global, must be before "L")
;L=0	show local IP interfaces (0..5, global)
;A=1	Font
;§=10	max Threads
;C=public ;SNMP Community

[*]	;Default-Set
;G=0
;i=1000
;t=60
VOIP-Client=1.1.1.240
VOIP-Server=1.1.1.1
Switches=2.0.0.1-5

[Academy]
;i=500
A.MLS=10.51.16.1
A.SWI=10.51.16.2
A.POE=10.51.16.3
A.RTR=10.51.16.254
B.MLS=10.52.16.1
DUDE=10.51.16.223
EDV=172.16.250.254
FW=172.16.0.231
INT=1.1.1.1

Code: Select all

; Define-Section

	EnableExplicit

	#Version="Free PB-Version"

	#DefaultSet="*"
	#AuswahlSet="?"

	Global DateiName.s="VPing.ini"		; Konfigurationsdatei
	Global Callback.i=0					; Rückgabewert des Callbacks (für On-Top-Knopf)
	Global Timeout.i=200					; Ping-Timeout
	Global Intervall.i=500					; Abstand zwischen Ping-Durchlauf
	Global Packetsize.i=60				; Packetgröße
	Global Packet.s						; Packetinhalt
	Global PingTTL.i						; TTL-Rückgabewert
	Global FlickerFree.i=0				; Flackern reduzieren
	Global ShowHistory.i=0				; History anzeigen
	Global Y_Height.i=16				; Höhe Balken
	Global Y_Title.i=22					; Höhe Überschrift
	Global Mshrink.i=7					; Schriftverkleinerung
	Global Nshrink.i=14					; Schriftverkleinerung
	Global Y_Width.i=2					; Fensterbreite
	Global Y_Gap.i=4					; Zwischenraum Überschrift/Balkenteil
	Global Y_Minigap.i=2					; Zwischenraum Balken
	Global pollcount.i=0					; Anzahl der Ping-Durchläufe
	Global pollzeit.i=0						; Zeitmesser
	Global fade.i=0						; Ausblenden
	Global bargraphics.i=0				; Balkengraphik
	Global hellerbalken.i=$fff4f4			; -"-
	Global dunklerbalken.i=$f4e8e8		; -"-
	Global punkt.i=$c0b0b0				; -"-
	Global OnTop.i=0					; Fenster im Vordergrund
	Global ShowLocal.i=0				; Lokale IP-Adresse(n) inkludieren
	Global StartLocal.i					; Erstes lokales Interface (1 oder 2)
	Global TotalLocals.i=0				; Anzahl der angezeigten lokalen Interfaces
	Global AdressUpdate.i=0			; Update der IP-Adressen (in sec)
	Global AdressUpdateTime.i=0		; Nächstes Update
	Global AdressUpdateActive.i=#False
	Global NoNetInit.i=#True			; Initialisierung
	Global GlobalSetting.i=#True		; zur Unterscheidung von 'X=' Einstellungen
	Global WsaVersion.i=$101			; WinSock-Version 1.1
	Global Community.s="public"			; SNMP Community

	Global Logging.i;						; Flag für Log-Datei
	Global NeverLogged.i=1;			; Flag für Log-Datei (es wurde noch kein Eintrag geschrieben)
	Global LoggingReady.i=0;			; Log-Datei geöffnet
	Global Zeit.SYSTEMTIME;				; genaue Zeitangabe (in ms)

	Global WindowsTitle.s=" VPing "+#Version

	Global StartZeit

	Global smallfont.i
	Global normalfont.i

	Global xborder
	Global yborder

	Global pausedebugmode.i
	Global hintergrund

	#Information="S"+#TAB$+"Fenstergröße (8..32)"+#CR$+"H"+#TAB$+"Überschrift (8..32)"+#CR$+"W"+#TAB$+"Fensterverbreiterung (0..32)"+#CR$+"M/N"+#TAB$+"Fontverkleinerung (0..32)"+#CR$+"F"+#TAB$+"Indikatoren (0:fix / 1:ausblenden)"+#CR$+"B"+#TAB$+"Balkengraphik (0:aus / 1:hell / 2:dunkel)"+#CR$+"D"+#TAB$+"Historydiagramm (0:aus / 1:Punkte)"+#CR$+"V"+#TAB$+"Videobuffer (0 / 1:kein Flackern)"+#CR$+"O"+#TAB$+"On top (0:aus / 1:an)"+#CR$+"T"+#TAB$+"Ping-Timeout (ms)"+#CR$+"I"+#TAB$+"Intervall zwischen Pings (ms)"+#CR$+	"P"+#TAB$+"Packetgröße (-Data / +Total Bytes)"+#CR$+"U"+#TAB$+"Update der DNS/Lokal-Adressen (s)"+#CR$+"G"+#TAB$+"Ergebnisse mitloggen (0..2)"+#CR$+"L"+#TAB$+"lokale IP-Interfaces anzeigen (0..5, global)"

	Structure IPAdresse
		Name.s
		IPname.s
		SNMPScan.i
		DeviceName.s
		DeviceType.s
		IPchange.i
		IP.i
		alivenow.i
		alivesum.i
		TTL.i
		timenow.i
		timesum.i
		timemin.i
		timemax.i
		alivecount.i
		alivecolorfade.i
		aliveseq.i
		deadcount.i
		deadcolorfade.i
		deadseq.i
		DNSUpdate.i
	EndStructure

	Enumeration
		#Alive_Down
		#Alive_Up
		#Alive_Undefined
	EndEnumeration

	#max=100								; maximale Anzahl der Ini-Konfigurationen
	Global Abschnitt.s						; Mehrfach-Konfigurationen
	Global AbschnittAktiv.i=#True	; während des Einlesens wichtig
	Global Dim Abschnitte.s(#max)	; Namen der Abschnitte (für Parameter '*')

	#MaxIP=100
	Global Dim Adresse.IPAdresse(#MaxIP)
	Global Dim ThreadIDs(#MaxIP)	; Anzahl der Threads
	Global Anzahl.i=1						; Anzahl der tatsächlichen IP-Adressen

	Global Dim Workaround(#MaxIP)


	Global Dim tab(19)
	tab(1) = 10		; IP
	tab(2) = 180		; Status
	tab(3) = 250		; Leerraum
	tab(4) = 260		; #Ok
	tab(5) = 300		; %Ok
	tab(6) = 380		; Leerraum
	tab(7) = 390		; TTL
	tab(8) = 430		; Leerraum
	tab(9) = 440		; akt
	tab(10) = 500	; durchschn
	tab(11) = 560	; max
	tab(12) = 620	; Leerraum
	tab(13) = 630	; alive
	tab(14) = 690	; Leerraum
	tab(15) = 700	; dead
	tab(16) = 750	; Leerraum
	tab(17) = 760	; name
	tab(18) = 870	; rechter Rand
	tab(19) = 880	; Fensterrand

	Declare.i Min(a.i,b.i)
	Declare.i Max(a.i,b.i)
	Declare.i Y(zeile)

; EndDefine

; Define SNMP-Informationen

	Enumeration
		#SNMP_Unknown;					kein Icon
		#SNMP_Successful;				(i)
		#SNMP_WrongCommunity;		/!\
		#SNMP_NoReply;					(×)
	EndEnumeration

	Global InfoText.s
	Global InfoID
	Global InfoMessage.MSG
	Global *InfoStruct.NMHDR
	Global *InfoText.TOOLTIPTEXT

	#GET=$A0

	#Field_Variable=10
	#SNMP_MaxPacketSize=548

	Structure Reference
		value.i
	EndStructure

	Global Dim SNMP_Message.s(#SNMP_NoReply)

	SNMP_Message(#SNMP_Unknown)="Keine Ping-Adresse"
	SNMP_Message(#SNMP_Successful)="SNMP Informationen"
	SNMP_Message(#SNMP_WrongCommunity)="Ungültige SNMP-Informationen"
	SNMP_Message(#SNMP_NoReply)="Keine SNMP-Antwort"

; EndDefine

; Logging
Procedure.s ExactTime()
	GetSystemTime_(@Zeit.SYSTEMTIME)
	ProcedureReturn "'"+RSet(Str((Zeit\wYear)%100),2,"0")+"/"+RSet(Str(Zeit\wMonth),2,"0")+"/"+RSet(Str(Zeit\wDay),2,"0")+" "+RSet(Str(Zeit\wHour),2,"0")+":"+RSet(Str(Zeit\wMinute),2,"0")+":"+RSet(Str(Zeit\wSecond),2,"0")+"."+RSet(Str(Zeit\wMilliseconds),3,"0")
EndProcedure
Procedure MakeLogFile()
	If LoggingReady=0
		If Logging>0
			If OpenFile(0,"Vping.log")
				FileSeek(0,Lof(0))
				LoggingReady=#True
			EndIf
		ElseIf Logging=0
			Logging=-1
		EndIf
	EndIf

	NeverLogged=#True

EndProcedure
Procedure CloseLogFile()
	If LoggingReady
		CloseFile(0)
	EndIf
EndProcedure
Procedure LogAll()

	Protected z

	#LoggingResponseTime=1;			Anwortzeit in Millisekunden oder "-", falls nicht erreichbar
	#LoggingReachableCounter=2;		+1,+2,... falls erreichbar, -1,-2,... falls nicht*

	;*) je nach gewählten Zeitintervallen können wir auch Ergebnisse, wie "-0, -0, -0, -3, -3, -3, -6,..." erhalten
	;    das könnte am ICMP selbst liegen. welches möglicherweise unnötig lange wartet und dann plötzlich einen
	;    Schwung von Negativ-Antworten liefert.
	;    Könnte evtl. behoben werden, in dem zu lange laufende Threads gekillt werden, z.Zt. per "Workaround"

	If Logging>0
		If NeverLogged
			NeverLogged=0
			WriteStringN(0,"")
			If Len(Abschnitt)
				WriteString(0,Abschnitt)
			Else
				WriteString(0,ExactTime())
			EndIf

			z=0
			While z<Anzahl
				z+1
				WriteString(0,#TAB$+Adresse(z)\IPname)
			Wend
			WriteString(0,#CRLF$)
		EndIf

		WriteString(0,ExactTime())
		z=0
		While z<Anzahl
			z+1
			If Logging=#LoggingResponseTime
				If Adresse(z)\Alivenow=#Alive_Up
					WriteString(0,#TAB$+Str(Adresse(z)\timenow))
				Else
					WriteString(0,#TAB$+"-")
				EndIf
			Else; #LoggingReachableCounter
				If Adresse(z)\Alivenow=#Alive_Up
					WriteString(0,#TAB$+"+"+Str(Adresse(z)\alivecount))
					Workaround(z)=0
				Else
					If Workaround(z)<Adresse(z)\deadcount
						Workaround(z)=Adresse(z)\deadcount
					Else
						Workaround(z)+1
					EndIf
					WriteString(0,#TAB$+"-"+Str(Workaround(z)))
				EndIf
			EndIf
		Wend
		WriteString(0,#CRLF$)
		;FlushFileBuffers(0)
	EndIf

EndProcedure

; Ping-Routinen
Procedure GetIPAddress(IPName.s)
	If Len(IPName) > 3  ; "n/a" aussparen
		ProcedureReturn MakeIPAddress(Val(StringField(IPName,1,".")),Val(StringField(IPName,2,".")),Val(StringField(IPName,3,".")),Val(StringField(IPName,4,".")))
	Else
		ProcedureReturn 0
	EndIf
EndProcedure
Procedure HostnameToIP(n)
	Protected ResultIP.s
	Protected wsa.wSAData
	Protected *host.HOSTENT
	Protected AdressNumber.i
	Protected IpAddress.i

	If Len(Adresse(n)\Name) > 0
		ResultIP.s="n/a"
		If WSAStartup_(WsaVersion, wsa) = #NOERROR
			*host = gethostbyname_(Adresse(n)\Name)
			If *host<>#Null
				; wozu alle Adressen einlesen???
				AdressNumber=0
				While PeekL(*host\h_addr_list+AdressNumber)
					IpAddress=PeekL(*host\h_addr_list+AdressNumber)
					ResultIP=StrU(PeekB(IpAddress),0)+"."+StrU(PeekB(IpAddress+1),0)+"."+StrU(PeekB(IpAddress+2),0)+"."+StrU(PeekB(IpAddress+3),0)
					AdressNumber+4
				Wend
			EndIf
			WSACleanup_() ; Close Windows sockets stuff...
		EndIf

		Adresse(n)\IPName=ResultIP
		Adresse(n)\IP=GetIPAddress(ResultIP)

	EndIf

EndProcedure
Procedure DNSHostnameToIP(n)

	Protected DNSThreadID.i
	Protected wait.i=500; 250ms

	DNSThreadID=CreateThread(@HostnameToIP(),n)

	While wait>0
		Delay(10)
		If IsThread(DNSThreadID)
			wait-1
			If wait=0
				KillThread(DNSThreadID)
				Delay(50)
				Adresse(n)\IPName="n/a"
				Adresse(n)\IP=0
			EndIf
		Else
			wait=0
		EndIf
	Wend

EndProcedure
Procedure Ping(IPAddress); Timeout und Message (durch Packet ersetzt) sind nun global
	; -2 Namensauflösung fehlgeschlagen // -1 Host nicht erreichbar // 0.. ms

	Protected ResultSize
	Protected *Result
	Protected *Echo.ICMP_ECHO_REPLY
	Protected hFile.i
	Protected Ergebnis.i

	ResultSize = SizeOf(ICMP_ECHO_REPLY)+Len(Packet); anstelle von Len(Message)
	*Result = AllocateMemory(ResultSize)
	*Echo.ICMP_ECHO_REPLY = *Result

	If IpAddress <> 0
		hFile = IcmpCreateFile_()
		Ergebnis=IcmpSendEcho_(hFile, IpAddress, Packet, Len(Packet), 0, *Result, ResultSize, Timeout+100)
		If Ergebnis>0
			Ergebnis=*Echo\RoundTripTime
			If Ergebnis>Timeout
				Ergebnis=-3
			Else
				PingTTL=*Echo\Options\Ttl & $000000FF
			EndIf
		Else
			Ergebnis=-1
		EndIf
		IcmpCloseHandle_(hFile)
	Else
		Ergebnis=-2
	EndIf

	FreeMemory(*Result)
	ProcedureReturn Ergebnis

EndProcedure

; Tools
Procedure.i Min(a.i,b.i)
	; Function: returns smaller of two numbers
	If a<b
		ProcedureReturn a
	Else
		ProcedureReturn b
	EndIf
EndProcedure
Procedure.i Max(a.i,b.i)
	; Function: returns smaller of two numbers
	If a>b
		ProcedureReturn a
	Else
		ProcedureReturn b
	EndIf
EndProcedure

; Allgemeine Routinen
Procedure.i GetParam(a.s,b.s,Defaultwert.i,min.i,max.i)
	Protected value.i
	Protected search.i

	value=Defaultwert

	search=FindString(a,";"+b+"=",1)
	If search
		value=Val(Mid(a,search+3,9));		3 Zeichen überspringen (";X=")
	EndIf

	value=min(value,max)
	value=max(value,min)

	;Debug value
	ProcedureReturn Value

EndProcedure
Procedure AdressenEinlesen()

	Protected FileHandle.i
	Protected Count.i
	Protected quit.i
	Protected start.i,rumpf.s,anfang.i,ende.i
	Protected pos.i
	Protected Line.s
	Protected TempAdresse.i
	Define Fehler.i=#True


	If FileSize(DateiName)
		FileHandle=ReadFile(#PB_Any,"VPing.ini")

		If FileHandle
			Fehler=#False

			If CountProgramParameters()
				Abschnitt=ProgramParameter()
				If Abschnitt<>""	; wegen Compiler-Fehlers...
					AbschnittAktiv=#False
				EndIf
			Else
				Abschnitt=#DefaultSet
			EndIf

			If (Abschnitt=#AuswahlSet) Or (GetKeyState_(#VK_SHIFT) & 128)

				OpenWindow(1, 0, 0, 200, 200," VPing Set auswählen...",#PB_Window_ScreenCentered | #PB_Window_SystemMenu)

				;CreateGadgetList(WindowID(1))
				;ListViewGadget(1, 5, 5, 190, 190) ; kann zwischen Tastatur- und Mausselektion nicht unterscheiden
				ListIconGadget(1, 5, 5, 190, 190,"VPing-Sets",186)
				;AddGadgetItem(1, -1, "",)
				AddGadgetItem(1, -1, "Default-Set")
				count.i=0

				Abschnitte(0)=#DefaultSet
				While Not(Eof(FileHandle)) And count<#max
					Line=Trim(ReadString(filehandle))
					quit=FindString(Line,"]",2)
					If (quit>0)
						If (FindString(Line,"[",1)=1) And (LCase(Mid(Line,2,quit-2))<>#DefaultSet)
							count+1
							Abschnitte(count)=Mid(line,2,quit-2)
							AddGadgetItem(1, -1, Abschnitte(count))
						EndIf
					EndIf
				Wend

				; anderen Fensterrahmen...
				SetWindowLong_(WindowID(1),#GWL_EXSTYLE,GetWindowLong_(WindowID(1),#GWL_EXSTYLE)| #WS_EX_TOOLWINDOW)
				SetWindowPos_(WindowID(1),#HWND_TOPMOST,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE|#SWP_FRAMECHANGED);#SWP_NOZORDER

				FileSeek(FileHandle,0)

				SetGadgetState(1, 0)
				SetActiveGadget(1)

				; ...und in den Vordergrund
				SetForegroundWindow_(WindowID(1)); geht nicht bei UPXten Files?

				quit.i=-1
				Repeat
					Define wait.i
					wait=WaitWindowEvent()
					Select Wait
					Case #PB_Event_Gadget
						If EventType()=0
							quit=GetGadgetState(1)
						EndIf
					Case #WM_CHAR
						Select EventwParam()
						Case 27
							quit=999
						Case 13,32
							quit=GetGadgetState(1)
						EndSelect

					Case #PB_Event_CloseWindow
						quit=999

					EndSelect
				Until quit>=0

				CloseWindow(1)

				Select quit
				Case 0
					Abschnitt=Abschnitte(quit)
					AbschnittAktiv=#True
				Case 1 To count
					Abschnitt=Abschnitte(quit)
					AbschnittAktiv=#False
				Case 1000
					Abschnitt=""
					AbschnittAktiv=#True
				Default
					End
				EndSelect

			EndIf

		EndIf

		;Else
		; entwerde eine Fehlermeldung...
		; MessageBox_(0,"'VPing.ini' nicht gefunden!","VPing Fehler", #MB_ICONERROR | #MB_OK)
		; End
	EndIf

	;MessageBox_(0,abschnitt,Str(AbschnittAktiv), icon | #MB_OK)


	Adresse(1)\Name="Localhost"
	Adresse(1)\IPName="127.0.0.1"
	Adresse(1)\IP=GetIPAddress(Adresse(1)\IPName)
	Adresse(1)\Timemin=9999
	Adresse(1)\alivenow=#Alive_Undefined

	If Fehler=0
		;MessageRequester("Fehler","Datei ''VPing.lst'' nicht gefunden...",0)
		;Else

		While Not(Eof(FileHandle))
			Line.s=Trim(ReadString(filehandle))

			; Parametereinstrellungen...
			If FindString(Line,";",1)=1 And (GlobalSetting Or AbschnittAktiv)

				quit=FindString(UCase(line),"C=",1)
				If quit
					Community=Trim(PeekS(@line+quit+1))
					quit=FindString(Community," ",1)
					If quit : Community=Left(Community,quit-1) : EndIf
					quit=FindString(Community,#TAB$,1)
					If quit : Community=Left(Community,quit-1) : EndIf
				Else

					line=UCase(line)

					Y_Height=GetParam(line,"S",Y_Height,8,32)
					Y_Title=GetParam(line,"H",Y_Height,8,32)
					Y_Width=GetParam(line,"W",Y_Width,0,32)
					Y_Minigap=GetParam(line,"Z",Y_Minigap,0,10)
					timeout=GetParam(line,"T",timeout,10,3000)
					intervall=GetParam(line,"I",intervall,10,5000)
					packetsize=GetParam(line,"P",packetsize,-10000,10000)
					fade=GetParam(line,"F",fade,0,1)
					Mshrink=GetParam(line,"M",Mshrink,4,32)
					Nshrink=GetParam(line,"N",Nshrink,4,32)
					flickerfree=GetParam(line,"V",flickerfree,0,1)
					bargraphics=GetParam(line,"B",bargraphics,0,2)
					ShowHistory=GetParam(line,"D",ShowHistory,0,1)
					OnTop=GetParam(line,"O",OnTop,0,1)
					ShowLocal=GetParam(line,"L",Showlocal,-5,5)
					Logging=GetParam(line,"G",Logging,-2,2)
					AdressUpdate=GetParam(line,"U",AdressUpdate,0,100)

					;die Zeile ";.=0" muss vor der Zeile ";L=" stehen, sonst werden alle Loop-Adressen ausgeblendet...
					If (GetParam(line,".",1,0,1)=0) And (Anzahl=1) And (Adresse(1)\IPName="127.0.0.1")
						Anzahl=0
					EndIf


					If ShowLocal And NoNetInit; "L=" nur einmal (global) ausführen...

						If ShowLocal<0		; negativ?
							ShowLocal=-ShowLocal
							If Anzahl=1		; Localhostzeile (127.0.0.1) streichen...
								Anzahl=0
							EndIf
						EndIf

						InitNetwork()
						NoNetInit=#False

						StartLocal=Anzahl	; erste Lokaladresse (1:nach oder 0:anstelle von 127.0.0.1)

						If ExamineIPAddresses()
							While ShowLocal
								ShowLocal-1
								TempAdresse=NextIPAddress()

								If TempAdresse
									Anzahl+1
									TotalLocals+1
									Adresse(Anzahl)\Name="Local #"+Str(TotalLocals)
									Adresse(Anzahl)\IPName=IPString(TempAdresse)
									Adresse(Anzahl)\IP=GetIPAddress(Adresse(Anzahl)\IPName)
									Adresse(Anzahl)\Timemin=9999
									Adresse(Anzahl)\alivenow=#Alive_Undefined
									Adresse(Anzahl)\DNSUpdate=#True ;nur für Bildschirmausgabe...
									Adresse(Anzahl)\SNMPScan=#SNMP_Unknown
								Else
									ShowLocal=0
								EndIf
							Wend
						EndIf
						;Debug zeit.l-GetTickCount_()
						ShowLocal=0
					EndIf

				EndIf

			ElseIf FindString(Line,"[",1)=1
				GlobalSetting=#False

				If FindString(LCase(Line),LCase(Abschnitt)+"]",2)=2	; falls notwendig: CharLower_(@Line)
					AbschnittAktiv=#True
				Else
					AbschnittAktiv=#False
				EndIf

			ElseIf Len(Line) And AbschnittAktiv

				If Anzahl<#MaxIP

					pos=FindString(Line,"=",1)

					If pos
						; Name für IP-Adresse angegeben, z.B.: Server=1.2.3.4
						Anzahl+1
						Adresse(Anzahl)\alivenow=#Alive_Undefined
						Adresse(Anzahl)\Name=Left(line,pos-1)
						Adresse(Anzahl)\IPName=Mid(line,pos+1,999)
						Adresse(Anzahl)\IP=GetIPAddress(Adresse(Anzahl)\IPName)
						Adresse(Anzahl)\SNMPScan=#SNMP_Unknown

					ElseIf (Asc(line)>47) And (Asc(line)<58)

						; auf IP-Bereich überprüfen, z.B.: 127.0.0.1-10
						pos=FindString(Line,"-",1)
						If pos>7	; Minus-Symbol darf nicht weiter links sein (1.2.3.4-5)
							start=pos-2
							While start>5 ; letzter IP-Trenner darf nicht weiter links sein (1.2.3.4-5)
								If Mid(line,start,1)="."
									Break
								EndIf
								start-1
							Wend
							If start>5
								rumpf.s=Left(line,start)									; 1.2.3.
								anfang.i=Val(Mid(line,start+1,pos-start-1))		; 4
								ende.i=Val(Mid(line,pos+1,999))					; 5

								; jeden IP-Eintrag nun "anlegen"...
								While (anfang<=Ende) And (anfang<256) And (anzahl<#MaxIP)
									anzahl+1
									Adresse(Anzahl)\alivenow=#Alive_Undefined
									Adresse(Anzahl)\Name=rumpf+Str(anfang)
									Adresse(Anzahl)\IPName=rumpf+Str(anfang)
									Adresse(Anzahl)\IP=GetIPAddress(Adresse(Anzahl)\IPName)
									Adresse(Anzahl)\SNMPScan=#SNMP_Unknown
									anfang+1
								Wend
							EndIf
						Else
							; normale IP-Adresse
							Anzahl+1
							Adresse(Anzahl)\alivenow=#Alive_Undefined
							Adresse(Anzahl)\Name=Line
							Adresse(Anzahl)\IPName=Line
							Adresse(Anzahl)\IP=GetIPAddress(Adresse(Anzahl)\IPName)
							Adresse(Anzahl)\SNMPScan=#SNMP_Unknown
						EndIf
					Else
						; Versuch, per Namensauflösung eine IP-Adresse zu bekommen...
						Anzahl+1
						Adresse(Anzahl)\alivenow=#Alive_Undefined
						Adresse(Anzahl)\Name=Line
						CreateThread(@DNSHostnameToIP(),Anzahl)
						Adresse(Anzahl)\DNSUpdate=#True
						Adresse(Anzahl)\SNMPScan=#SNMP_Unknown
					EndIf
				EndIf
				;Debug Line
			EndIf
		Wend

		CloseFile(FileHandle)

		Timeout=min(Intervall,Timeout) ; Timeout limitieren...

		If Packetsize<0
			Packetsize=-Packetsize+42 ; 14(Ethernet) + 20(IP) + 8(ICMP) Byte  // evtl. noch + 4 (CRC) Byte
		EndIf

		Packet=LSet("<-  VPing "+#Version+"  -  (c) 2012 by Michael Vogel  -",Packetsize-42,">")

		;CreateFile(1,"f:\Debug.log")
		;WriteStringN(1,Packet)
		;WriteStringN(1,Str(Packetsize))
		;CloseFile(1)

		If bargraphics=2
			hellerbalken=$ffe0e0
			dunklerbalken=$ffd0d0
		EndIf

	EndIf
EndProcedure
Procedure Callback(WindowID,Message,wParam,lParam)

	Select Message

	Case #WM_SYSCOMMAND
		If wParam=#SC_MAXIMIZE
			Callback=1
			ProcedureReturn 0
		EndIf

	Case #WM_MOUSEMOVE
		InfoMessage\hwnd=WindowID
		InfoMessage\message=Message
		InfoMessage\wParam=wParam
		InfoMessage\lParam=lParam
		SendMessage_(InfoID,#TTM_RELAYEVENT,0,InfoMessage)

	Case #WM_NOTIFY
		*InfoStruct=lParam
		If *InfoStruct\code=#TTN_NEEDTEXT
			*InfoText=lParam
			With Adresse(*InfoText\hdr\idFrom)
				SendMessage_(InfoID,#TTM_SETTITLE,\SNMPScan,SNMP_Message(\SNMPScan))
				InfoText=\IPName+ " ("+\Name+")";+Str(*InfoText\hdr\idFrom)
				If \SNMPScan=#SNMP_Successful
					InfoText+#CR$+\DeviceName+#CR$+\DeviceType
				EndIf

			EndWith
			*InfoText\lpszText=@InfoText
		EndIf
	EndSelect

	ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

; GUI
Procedure Init()

	Define i.i
	Define xsize.i,ysize.i

	AdressenEinlesen()

	If Len(Abschnitt)
		If Abschnitt=#DefaultSet
			Abschnitt="Default-Set"
		EndIf
		WindowsTitle+"  •  "+Abschnitt
		Abschnitt="["+Abschnitt+"]"
	EndIf

	i=Year(Date())

	Y_Height=Max(Y_Height,4)
	Mshrink=Min(Mshrink,Y_Height-1);

	Y_Title=Max(Y_Title,4)
	Nshrink=Min(Nshrink,Y_Title-1);

	; Abstand zwischen Hauptfenster und Über/Unterschriftsbereich leicht anpassen
	Y_Gap+Y_Minigap>>1

	StartZeit=0


	For i=1 To 19
		tab(i) = (tab(i)*Y_Height)>>5+Y_Width*i
		If i>17
			tab(i)+Y_Width
		EndIf
	Next i

	Global Dim Alive.s(2)
	Alive(0)="Dead"
	Alive(1)="Alive"
	Alive(2)="n/a"

	;Fontname.s="MS Sans"
	;Global Small=CreateFont_(height-sub-add,0,0,0,500,0,0,0,#ANSI_CHARSET,#OUT_DEFAULT_PRECIS,#CLIP_DEFAULT_PRECIS,#DEFAULT_QUALITY,#DEFAULT_PITCH,*Fontname)
	;Global Font=CreateFont_(height-sub,0,0,0,500,0,0,0,#ANSI_CHARSET,#OUT_DEFAULT_PRECIS,#CLIP_DEFAULT_PRECIS,#PROOF_QUALITY,#DEFAULT_PITCH,*Fontname)

	smallfont=LoadFont(#PB_Any,"MS Sans",Y_Title-Nshrink)
	normalfont=LoadFont(#PB_Any,"MS Sans",Y_Height-Mshrink)

	xborder=GetSystemMetrics_(#SM_CXBORDER)<<1
	yborder=GetSystemMetrics_(#SM_CYBORDER)<<1;+GetSystemMetrics_(#SM_CYCAPTION)

	tab(19)+xborder
	xsize=tab(19)
	ysize=y(anzahl+1)+yborder+Y_Title
	;d_& = tab(7) - tab(6)  // Spaltenbreite für Zeitbalken

	; History
	Global Dim HistoryNow(Anzahl,Y_Height)
	Global Dim HistoryMed(Anzahl,Y_Height)
	Global Dim HistoryMax(Anzahl,Y_Height)

	OpenWindow(0,40,40,xsize,ysize,WindowsTitle,#PB_Window_SystemMenu | #PB_Window_MinimizeGadget |#PB_Window_MaximizeGadget)
	;SetWindowLong_(WindowID(0),#GWL_EXSTYLE,GetWindowLong_(WindowID(0),#GWL_EXSTYLE)|#WS_EX_CONTEXTHELP)
	;SetWindowPos_(WindowID(0),0,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE|#SWP_FRAMECHANGED|#SWP_NOZORDER)

	;SetWindowLong_(WindowID(0),#GWL_EXSTYLE,GetWindowLong_(WindowID(0),#GWL_EXSTYLE)|#WS_EX_LAYERED|#WS_EX_TOOLWINDOW)
	;SetLayeredWindowAttributes_(WindowID(0),0,99,#LWA_ALPHA)

	#TTS_NOFADE=$20
	#TTS_NOANIMATE=$10

	InfoID=CreateWindowEx_(0,"Tooltips_Class32","",#TTS_ALWAYSTIP|#TTS_NOFADE|#TTS_NOANIMATE|#WS_EX_TOPMOST,0,0,0,0,0,0,0,0);#TTS_BALLOON
	SendMessage_(InfoID,#TTM_SETTITLE,2,"Keine Informationen vorhanden")
	SendMessage_(InfoID,#TTM_SETMAXTIPWIDTH,0,240)
	;SendMessage_(InfoID,#TTM_SETTITLE,1,"SNMP Informationen")

	Protected InfoTool.TOOLINFO
	InfoTool\cbSize=SizeOf(TOOLINFO)
	InfoTool\uFlags=#TTF_CENTERTIP
	InfoTool\hwnd=WindowID(0)
	InfoTool\lpszText=#LPSTR_TEXTCALLBACK

	For i=1 To Anzahl
		InfoTool\uId=i
		SetRect_(@InfoTool\rect,0,Y(i),tab(2),Y(i)+Y_Height)
		SendMessage_(InfoID,#TTM_ADDTOOL,0,InfoTool)
	Next i

	StickyWindow(0,OnTop)
	SetWindowPos_(InfoID,#HWND_TOPMOST,0,0,0,0,#SWP_NOREDRAW|#SWP_NOMOVE|#SWP_NOSIZE); ****

	If flickerfree
		InitSprite()
		OpenWindowedScreen(WindowID(0), 0,0, xsize,ysize, 0,0,0)
	EndIf

	SetWindowCallback(@callback(),0)

	pausedebugmode.i=0
	hintergrund=GetSysColor_(#COLOR_BTNFACE)

EndProcedure
Procedure Balken(n.i,z,y,wert.i)
	Define color.i

	If bargraphics
		If z&1
			color=hellerbalken; $ffe8e8
		Else
			color=dunklerbalken; $ffe0e0
		EndIf

		Box(tab(n)+1,y+1,max(1,(tab(n+1)-tab(n)-2)*min(wert,Timeout)/Timeout),Y_Height-2,color)
	EndIf
EndProcedure
Procedure.s Strich(n)
	If n
		ProcedureReturn Str(n)
	Else
		ProcedureReturn "-"
	EndIf
EndProcedure
Procedure.i Y(zeile)
	Select zeile
	Case 0
		ProcedureReturn 0
	Case Anzahl+1
		ProcedureReturn Anzahl*(Y_Height+Y_Minigap)-Y_Minigap+Y_Title+Y_Gap<<1
	Case -1
		ProcedureReturn Y_Title+Y_Gap>>1
	Case -2
		ProcedureReturn Y_Title+Anzahl*(Y_Height+Y_Minigap)-Y_Minigap+Y_Gap+Y_Gap>>1
	Default
		ProcedureReturn (zeile-1)*(Y_Height+Y_Minigap)+Y_Title+Y_Gap
	EndSelect
EndProcedure
Procedure.i Z(zeile)
	Select zeile
	Case 0,Anzahl+1
		ProcedureReturn Y(zeile)+Nshrink>>1-(Y_Title-Nshrink)>>2
	Default
		; Schrift in die Mitte rücken (+ Verkleinerung - Schriftversatz von Arial)
		ProcedureReturn Y(zeile)+Mshrink>>1-(Y_Height-Mshrink)>>2
	EndSelect
EndProcedure

; SNMP (auf Minimum reduziert)
Procedure.i BE_Length(*memory,*pos.Reference)

	; Calculates length of actual field...

	Protected byte
	Protected length
	Protected n

	byte=PeekB(*memory+*pos\Value)
	*pos\Value+1

	If byte&$80;				multi-byte length
		byte&$3;				number of bytes for length information

		While byte
			length<<8
			length+(PeekB(*memory+*pos\Value)&$ff)
			byte-1
			*pos\Value+1
		Wend
	Else
		length=byte&$7f
	EndIf

	;Debug "Len: "+Str(length)

	ProcedureReturn length

EndProcedure
Procedure.i BM_Integer(value.i,*memory,*pos.Reference)

	; Writes integer value into memory, starting at position *pos
	; Returns number of used Bytes...

	If (value<$80)
		PokeB(*memory+*pos\Value,value)
		value=1
	Else
		PokeB(*memory+*pos\Value,(value>>8)&$ff)
		PokeB(*memory+*pos\Value+1,value&$ff)
		value=2
	EndIf

	*pos\Value+value
	ProcedureReturn value

EndProcedure
Procedure.i BM_Value(value.i,*memory,*pos.Reference)
	; should use quads, but because of pures poor quad handling limited to long for now ;(

	; Writes integer value into memory, starting at position *pos
	; Returns number of used Bytes...

	If (value>=0) And (value<128)
		PokeB(*memory+*pos\Value,value)
		value=1
	Else
		value=0
	EndIf

	*pos\Value+value
	ProcedureReturn value

EndProcedure
Procedure.i BM_String(value.s,*memory,*pos.Reference)

	; Writes string value into memory, starting at position *pos
	; Returns number of used Bytes...

	Protected length=Len(value)

	If length
		PokeS(*memory+*pos\Value,value,length)
		*pos\Value+length
	EndIf

	ProcedureReturn length

EndProcedure
Procedure.i BM_Object(OID.s,*memory,*pos.Reference)

	; Writes OID object into memory starting at position *pos
	; Returns number of used bytes

	Protected i
	Protected length=0

	length+BM_Value(43,*memory,*pos)

	For i=1 To 7
		length+BM_Value(Val(StringField(OID,i,".")),*memory,*pos)
	Next

	ProcedureReturn length

EndProcedure
Procedure.i BM_Move(value.i,length.i,*memory,*pos.Reference)

	; Insert byte value into memory block...
	; Returns total length

	; Auf Anregung von "Infratec" habe ich CopyMemory gegen MoveMemory getauscht...
	MoveMemory(*memory+*pos\Value-length,*memory+*pos\Value-length+2,length)
	PokeB(*memory+*pos\Value-length,value)
	PokeB(*memory+*pos\Value-length+1,length)

	*pos\Value+2
	ProcedureReturn length+2

EndProcedure
Procedure.i BM_Null(value.i,*memory,*pos.Reference)

	; Writes byte value into memory address...
	; Returns length (=2)

	PokeB(*memory+*pos\Value,value)
	PokeB(*memory+*pos\Value+1,0)

	*pos\Value+2
	ProcedureReturn 2

EndProcedure
Procedure.i PDU_Check(n,*memory)

	Protected byte
	Protected length
	Protected pos

	Protected field
	Protected Value.s

	pos=0
	Repeat

		byte=PeekB(*memory+pos)&$ff

		pos+1
		length=BE_Length(*memory,@pos);

		If byte&$e0=0

			If (byte=4) And (field=#Field_Variable)
				Value=PeekS(*memory+pos,length)
				If n>Anzahl
					n-Anzahl
					Adresse(n)\DeviceName=Value
				Else
					Adresse(n)\DeviceType=Value
				EndIf
				If Len(Value)
					; "gültige" SNMP-Antwort...
					Adresse(n)\SNMPScan=#SNMP_Successful
				EndIf
			EndIf

			pos+length

		EndIf

		field+1
	Until field>#Field_Variable

	ProcedureReturn 0


EndProcedure

Procedure.i PDU_Make(n,*memory)

	; compose SNMP packet into reserved memory (548 bytes)
	; n = Request number

	; Returns packet length

	Protected length
	Protected pos
	Protected PositionA,PositionB

	; SNMPv1
	length=BM_Value($00,*memory,@pos)
	length=BM_Move($02,length,*memory,@pos)

	; Community
	length=BM_String(Community,*memory,@pos)
	length=BM_Move($04,length,*memory,@pos)

	PositionA=pos

	; Request ID
	length=BM_Integer(n,*memory,@pos)
	length=BM_Move($02,length,*memory,@pos)

	; Error-Status
	length=BM_Value(0,*memory,@pos)
	length=BM_Move($02,length,*memory,@pos)

	; Error-Index
	length=BM_Value(0,*memory,@pos)
	length=BM_Move($02,length,*memory,@pos)

	PositionB=pos

	; OID
	length=BM_Object("6.1.2.1.1."+Chr('1'+((n-1)/Anzahl)<<2)+".0",*memory,@pos); 1 oder 5
	length=BM_Move($06,length,*memory,@pos)

	; NULL
	length=BM_Null($05,*memory,@pos)

	; Envelope OID and Null-field (two times)
	length=BM_Move($30,pos-PositionB,*memory,@pos)
	length=BM_Move($30,pos-PositionB,*memory,@pos)

	; Envelope Request-ID, Error Information and OID-Envelope
	length=BM_Move(#GET,pos-PositionA,*memory,@pos)

	; Envelope all SNMP fields
	length=BM_Move($30,pos,*memory,@pos)

	ProcedureReturn pos

EndProcedure
Procedure.i SNMP_Get(n)

	Protected *pointer
	Protected *Buffer
	Protected Status
	Protected Start
	Protected SockInfo.sockaddr_in
	Protected SockIdent

	With Adresse(1+(n-1)%Anzahl)

		If \IP
			*pointer=Sockinfo
			sockinfo\sin_family=#AF_INET
			sockinfo\sin_port=htons_(161)
			sockinfo\sin_addr=\IP

			SockIdent=SOCKET_(#AF_INET,2,0)

			If SockIdent<>#INVALID_SOCKET

				*Buffer=AllocateMemory(#SNMP_MaxPacketSize)

				If *Buffer
					Status=PDU_Make(n,*Buffer)

					If Status
						If  sendto_(SockIdent,*Buffer,Status,0,*pointer,SizeOf(sockaddr_in)) <> #SOCKET_ERROR

							; SNMP-Anfrage geschickt... (noch keine Antwort)
							If \SNMPscan=#SNMP_Unknown : \SNMPscan=#SNMP_NoReply : EndIf

							;Status=0
							Start=Date()
							Repeat
								Delay(1)
								Status=recv_(SockIdent,*Buffer,#SNMP_MaxPacketSize,2)
								If Date()-Start>5
									Status=#SOCKET_ERROR
								EndIf
							Until Status<>0

							If Status<>#SOCKET_ERROR
								;ReAllocateMemory(*Buffer,Status)
								; SNMP-Antwort erhalten... (aber nicht unbedingt eine gültige Antwort)
								If \SNMPscan%#SNMP_NoReply=#SNMP_Unknown : \SNMPscan=#SNMP_WrongCommunity : EndIf
								Status=PDU_Check(n,*Buffer)
							Else
								Status=0
							EndIf

						EndIf
					EndIf
					FreeMemory(*Buffer)

				EndIf

			EndIf
		EndIf

	EndWith

	ProcedureReturn Status

EndProcedure

; Ping & Co
Procedure Write(spalte,zeile,text.s)
	Define x.i
	x=tab(spalte)
	Select spalte
	Case 2 To 16
		x=(tab(spalte+1)+tab(spalte)-TextWidth(text))/2
	EndSelect
	DrawText(x,z(zeile),text,#Black)
EndProcedure
Procedure WriteAll()
	Protected i,n
	Define y.i
	Define z.i
	Define color.i
	Define wert.i
	Define Sekunden.i

	If flickerfree
		ClearScreen(hintergrund)
		StartDrawing(ScreenOutput())
	Else
		StartDrawing(WindowOutput(0))
	EndIf

	DrawingFont(FontID(smallfont))
	BackColor(hintergrund)
	;DrawingMode(1)

	write(1,0,"Adresse")
	write(2,0,"Status")
	write(4,0,"#Ok")
	write(5,0,"%Ok")
	write(7,0,"TTL")
	write(9,0,"akt.")
	write(10,0,"Ø")
	write(11,0,"max.")
	write(13,0,"Alive")
	write(15,0,"Dead")
	write(17,0,"Name")

	Sekunden=(GetTickCount_()-StartZeit)/1000
	write(1,Anzahl+1,"Ping-Statistik: ")
	write(2,Anzahl+1,"  "+Str(-pollzeit)+"ms  ")
	write(4,Anzahl+1,"  "+Str(pollcount)+"x  ")
	write(5,Anzahl+1,"  "+Str(Sekunden)+"s  ")
	;
	;write(2,Anzahl+1,"  Zeit: "+Str((GetTickCount_()-StartZeit)/1000)+"s  ")
	;write(4,Anzahl+1,"  Ping: "+Str(pollcount)+"  ")
	;write(5,Anzahl+1," =100%")
	write(10,Anzahl+1,"Intervall: "+Str(intervall)+"ms  /  Timeout: "+Str(Timeout)+"ms")


	Select PauseDebugMode
	Case 0
		If pollcount<2	; eigentlich =1, kann aber manchmal auch noch 0 sein...
			AdressUpdateTime=Sekunden+AdressUpdate
			BackColor($ffffff)
			write(17,Anzahl+1," Restart... ")
		ElseIf AdressUpdate And (Sekunden>=AdressUpdateTime)
			AdressUpdateTime=Sekunden+AdressUpdate
			AdressUpdateActive=#True
			BackColor($40c0f0)
			write(17,Anzahl+1," Adressen ")
		ElseIf Logging>0
			BackColor($BAE2FE)
			write(17,Anzahl+1,"  Logging  ")
		Else
			BackColor(hintergrund)
			write(17,Anzahl+1," Running     ")

		EndIf

	Case 1
		BackColor($00ffff)
		write(17,Anzahl+1," P A U S E ")
	Case 2
		BackColor($00ffff)
		write(17,Anzahl+1," D E B U G ")
	EndSelect

	For z=-2 To -1
		y=y(z) ;*(height+add)-add-1

		FrontColor($fff0f0)
		LineXY(0,y,tab(19),y)
		FrontColor($D0c0c0)
		LineXY(0,y-1,tab(19),y-1)
		FrontColor(0)
	Next z

	z=0

	While z<Anzahl
		z+1

		y=y(z)

		If z&1
			color=$fff8f8
		Else
			color=$ffe8e8
		EndIf

		Box(0,y,tab(19),Y_Height,color)

		DrawingFont(FontID(normalfont))
		DrawingMode(1)

		;With Adresse()

		Select Adresse(z)\Alivenow
		Case #Alive_Down
			color=$4040f0
		Case #Alive_Up
			color=$40f000
		Case #Alive_Undefined
			color=$40f0f0
		EndSelect

		Box(tab(2),y,tab(3)-tab(2),Y_Height,color)

		If Adresse(z)\IPchange>0
			If fade
				Adresse(z)\IPchange-1
				color=$a0d8f8-$180a02*Adresse(z)\IPchange
			Else
				Adresse(z)\IPchange=0
				color=$40c0f0
			EndIf
			Box(tab(1)/2,y,tab(2)-tab(1),Y_Height,color)
		EndIf

		If AdressUpdateActive And Adresse(z)\DNSupdate
			write(1,z,Adresse(z)\IPName+"*")
		Else
			write(1,z,Adresse(z)\IPName)
		EndIf

		write(1,z,Adresse(z)\IPName)
		write(2,z,alive(Adresse(z)\Alivenow))
		write(4,z,Str(Adresse(z)\Alivesum))
		If Adresse(z)\Alivesum>0
			If Adresse(z)\Alivenow
				write(7,z,Str(Adresse(z)\TTL))
				balken(9,z,y,Adresse(z)\timenow)
			EndIf
			If ShowHistory
				n=tab(10)-tab(9)-2
				For i=1 To Y_Height-2
					If HistoryNow(z,i)>=0
						Plot(tab(9)+max(1,n*min(HistoryNow(z,i),Timeout)/Timeout),y+i,punkt)
					EndIf
				Next i
			EndIf
			If Adresse(z)\Alivenow

				write(9,z,Str(Adresse(z)\timenow))
			Else
				write(7,z,"-")
				write(9,z,"-")
			EndIf
			write(5,z,StrF(100.0*Adresse(z)\Alivesum/(pollcount),1))

			wert=Adresse(z)\timesum/Adresse(z)\Alivesum
			balken(10,z,y,wert)
			If ShowHistory
				HistoryMed(z,Y_Height-1)=wert
				n=tab(11)-tab(10)-2
				For i=1 To Y_Height-2
					HistoryMed(z,i)=HistoryMed(z,i+1)
					Plot(tab(10)+max(1,n*min(HistoryMed(z,i),Timeout)/Timeout),y+i,punkt)
				Next i
			EndIf
			write(10,z,Str(wert))

			wert=Adresse(z)\timemax
			balken(11,z,y,wert)
			If ShowHistory
				HistoryMax(z,Y_Height-1)=wert
				n=tab(12)-tab(11)-2
				For i=1 To Y_Height-2
					HistoryMax(z,i)=HistoryMax(z,i+1)
					Plot(tab(11)+max(1,n*min(HistoryMax(z,i),Timeout)/Timeout),y+i,punkt)
				Next i
			EndIf
			write(11,z,Str(wert))

			If Adresse(z)\aliveseq>0 And Adresse(z)\aliveseq=Adresse(z)\alivecount
				Box(tab(13),y,tab(14)-tab(13),Y_Height,$40f040)
				If fade : Adresse(z)\Alivecolorfade=3 : EndIf
			ElseIf Adresse(z)\Alivecolorfade
				Adresse(z)\Alivecolorfade-1
				Box(tab(13),y,tab(14)-tab(13),Y_Height,$d0f0d0-$100010*Adresse(z)\alivecolorfade)
			EndIf
			write(13,z,Strich(Adresse(z)\aliveseq))
			If Adresse(z)\deadseq>0 And Adresse(z)\deadseq=Adresse(z)\deadcount
				Box(tab(15),y,tab(16)-tab(15),Y_Height,$4040f0)
				If fade : Adresse(z)\Deadcolorfade=3 : EndIf
			ElseIf Adresse(z)\Deadcolorfade
				Adresse(z)\Deadcolorfade-1
				Box(tab(15),y,tab(16)-tab(15),Y_Height,$d0d0f0-$101000*Adresse(z)\deadcolorfade)
			EndIf
			write(15,z,Strich(Adresse(z)\deadseq))
		Else
			write(5,z,"n/a")
			write(7,z,"n/a")
			write(9,z,"n/a")
			write(10,z,"n/a")
			write(11,z,"n/a")
			write(13,z,"n/a")
			write(15,z,"n/a")
		EndIf
		write(17,z,Adresse(z)\Name)

	Wend


	StopDrawing()
	If flickerfree
		FlipBuffers()
	EndIf


EndProcedure

Procedure PollOne(record.i)

	Protected result.i
	Protected i

	;SelectElement(Adresse(), test)

	With Adresse(record)
		If pausedebugmode
			Result=Random(3)-1
			If result>0 : Result=Random(Timeout) : EndIf
		Else
			Result=Ping(\IP)
			Debug Hex(\IP)+": "+Str(result)+" !"
			;Delay(Random(100+20))
		EndIf

		If Result<0
			\Alivenow=#Alive_Down
			\Alivecount=0
			\Deadcount+1
			\Deadseq=Max(\Deadcount,\Deadseq)
			;DrawText(10,y,\Name+" = "+\IP+"   dead  "+Str(128-PingGetTTL())+" Hop")
		Else
			\Alivenow=#Alive_Up
			\Alivesum+1
			\Alivecount+1
			\Deadcount=0
			\Timenow=Result
			\Timesum+Result
			\Timemin=Min(Result,\Timemin)
			\Timemax=Max(Result,\Timemax)
			\Aliveseq=Max(\Alivecount,\Aliveseq)
			\TTL=PingTTL

			; bei gültiger IP-Adresse ein einziges Mal SNMP-Infos holen...
			If \SNMPScan=#SNMP_Unknown
				SNMP_Get(record);				Geräte-Typ
				SNMP_Get(record+Anzahl);	Geräte-Name
			EndIf
		EndIf

		If ShowHistory
			For i=1 To Y_Height-3
				HistoryNow(record,i)=HistoryNow(record,i+1)
			Next i
			HistoryNow(record,Y_Height-2)=result
		EndIf

	EndWith

EndProcedure
Procedure PollAll()

	Define zeiger.i
	Define delay.i
	Define ActiveThreads.i
	Define i.i
	Define TempAdresse.i

	pollzeit=GetTickCount_()
	pollcount+1

	zeiger=0

	While zeiger<Anzahl
		zeiger+1
		ThreadIDs(zeiger)=CreateThread(@PollOne(),zeiger)
	Wend

	; Adress-Updates (lokale IP-Ports und DNS-Namen)...
	If AdressUpdateActive
		i=0

		If TotalLocals;	lokale Adressen überprüfen (DHCP)
			If ExamineIPAddresses()
				While i<TotalLocals
					i+1
					TempAdresse=NextIPAddress()
					If TempAdresse<>Adresse(StartLocal+i)\IP; Or Random(2)=0; fürs Testen...
						Adresse(StartLocal+i)\IPchange=5
						If TempAdresse
							Adresse(StartLocal+i)\Name="Local #"+Str(i)
							Adresse(StartLocal+i)\IPName=IPString(TempAdresse)
							Adresse(StartLocal+i)\IP=TempAdresse
						Else
							Adresse(StartLocal+i)\Name="n/a"
							Adresse(StartLocal+i)\IPName="n/a"
							Adresse(StartLocal+i)\IP=0
						EndIf
					EndIf
				Wend
			EndIf
		EndIf

		i+StartLocal;	Zähler auf Absolutwert bringen

		While i<Anzahl;		DNS-Updates durchführen
			i+1
			If Adresse(i)\DNSUpdate
				CreateThread(@DNSHostnameToIP(),i)

				TempAdresse=GetIPAddress(Adresse(i)\IPName)
				If TempAdresse<>Adresse(i)\IP; Or Random(3)=0; fürs Testen...
					Adresse(i)\IP=TempAdresse
					Adresse(i)\IPchange=5
				EndIf
			EndIf
		Wend

		AdressUpdateActive=#False
	EndIf

	; so, jetzt geben wir allen Threads ein wenig Zeit zum fertig werden...
	delay=0
	Repeat
		delay+1
		Delay(Timeout>>2)
		ActiveThreads=0
		zeiger=0
		While zeiger<Anzahl
			zeiger+1
			activethreads+IsThread(ThreadIDs(zeiger))
		Wend
		; Debug Str(delay)+": "+Str(ActiveThreads)
	Until (Activethreads=0) Or (delay=5)

	pollzeit-GetTickCount_()

EndProcedure
Procedure ResetAll()
	Define y.i
	Define z.i

	pollcount=0
	StartZeit=GetTickCount_()-intervall

	z=0

	While z<=Anzahl
		y+1
		Adresse(z)\SNMPScan=#SNMP_NoReply
		Adresse(z)\DeviceType=""
		Adresse(z)\DeviceName=""
		Adresse(z)\IPchange=0
		Adresse(z)\Alivenow=#Alive_Undefined
		Adresse(z)\Alivesum=0
		Adresse(z)\TTL=0
		Adresse(z)\Alivecount=0
		Adresse(z)\Deadcount=0
		Adresse(z)\Timenow=0
		Adresse(z)\Timesum=0
		Adresse(z)\Timemin=0
		Adresse(z)\Timemax=0
		Adresse(z)\Aliveseq=0
		Adresse(z)\Deadseq=0
		Adresse(z)\Alivecolorfade=0
		Adresse(z)\Deadcolorfade=0
		z+1
	Wend

EndProcedure
Procedure Ende()

	;DeleteObject_(small)
	;DeleteObject_(font)
	FreeFont(smallfont)
	FreeFont(normalfont)

	CloseLogFile()
	CloseWindow(0)

	If flickerfree
		CloseScreen()
	EndIf

EndProcedure

; Hauptprogramm
Procedure Main()
	Define exit.i

	Init()

	;PollOne(1)
	;ttlvalue=PingGetTTL()

	exit=0
	StartZeit=GetTickCount_()-intervall
	AddWindowTimer(0,1,intervall)

	MakeLogfile()

	WriteAll()
	PollAll()
	LogAll()
	WriteAll()

	Define event.i
	Repeat

		Event=WaitWindowEvent()

		Select Event

		Case #PB_Event_CloseWindow
			exit=99

		Case #WM_CHAR
			Select EventwParam()
			Case #ESC
				exit=99
			Case ' '
				pausedebugmode=pausedebugmode!1&1
			Case '@'
				pausedebugmode=pausedebugmode!2&2
			Case '!'
				ShowHistory=1-ShowHistory
			Case '0',13
				ResetAll()
			Case 'l','L'
				Logging=-Logging
				If Logging>0
					MakeLogFile()
				EndIf

			Case '?'
				MessageRequester(" Übersicht der Ini-Befehle",#Information);,#MB_ICONASTERISK)
			EndSelect

		Case #PB_Event_Timer
			If EventTimer()=1; Timer-Nummer (da es durch ToolTip auch plötzlich andere Events gibt)...
				If pausedebugmode=1
					StartZeit+intervall
				Else
					PollAll()
					LogAll()
				EndIf
				WriteAll()
			EndIf


		Case #WM_PAINT
			WriteAll()

		EndSelect

		If Callback
			Callback=0
			OnTop=1-OnTop
			StickyWindow(0,OnTop); ****
		EndIf

	Until exit

	Ende()
EndProcedure

Main()

lesserpanda
User
User
Posts: 65
Joined: Tue Feb 11, 2020 7:50 am

Re: Windows platform - network diagnostic app

Post by lesserpanda »

Thank you everyone! I will work out code.
Post Reply