List resources on local area network

Share your advanced PureBasic knowledge/code with the community.
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

List resources on local area network

Post by Hi-Toro »

Hello all,

I thought I'd post this since it might be useful to others -- it looks up and lists all resources on a Windows LAN (dunno what'll happen if you have a Linux or other PC attached!), showing sizes of shared disks and computer names/IP addresses (the IP lookup is Flype's code).

I've no idea how well it'll work with a router/switch, but it works on my setup, which is a server that has two PCs going directly into it.

I've made it as fault-proof as possible, but it just shows how to retrieve this information and prints it to the Debug Output window.

I think it should work with Windows 2000 or above. Don't be surprised if it appears to pause for long periods, as Windows can take its time in finding network resources! I've never understood why this is...

(The only minor thing bugging me at the moment is that it prints the public IP for the client running the program, rather than the LAN IP, though it lists the other PCs on the LAN with their local IPs.)

Code: Select all


; TURN ON DEBUGGER TO SEE THE OUTPUT!

Procedure.s GetIP (ComputerName.s)
	; By Flype! (Just reformatted to my preference.)
	If ComputerName
		If WSAStartup_ ((1<<8|1), wsa.WSADATA) = #NOERROR
			*host.HOSTENT = gethostbyname_ (ComputerName)
			WSACleanup_ ()
			If *host
				ProcedureReturn PeekS (inet_ntoa_ (PeekL (PeekL (*host\h_addr_list))))
			EndIf
		EndIf
	EndIf
EndProcedure

; -----------------------------------------------------------------------------
; Enumerate LAN resources...
; -----------------------------------------------------------------------------

Procedure ShowNetworkInfo (*resource.NETRESOURCE = #Null, indent = 0)

	; Indent string for debugging recursive function...

	in$ = LSet ("", 8 * indent, "-")
	If indent > 0
		in$ = in$ + "> "
	EndIf

	chunk = 262144 ; 4 times the M$-suggested amount (in 1992-1996)...
	
	openresult = WNetOpenEnum_ (#RESOURCE_GLOBALNET, #RESOURCETYPE_ANY, 0, *resource, @enum)
	
	Select openresult
	
		Case #NO_ERROR

			size = chunk
			
			; Try to enumerate resources. In the unlikely event that the buffer is too small,
			; add another 'chunk' of memory until OK...
			
			; Probably won't be relevant except for massive business networks anyway...
			
			Repeat
	
				count = $FFFFFFFF
	
				*mem = ReAllocateMemory (*mem, size)
	
				enumresult = WNetEnumResource_ (enum, @count, *mem, @size)
				
				If enumresult = #ERROR_MORE_DATA
					size = size + chunk
				EndIf
				
			Until enumresult <> #ERROR_MORE_DATA
			
			Select enumresult
			
				Case #NO_ERROR
	
					; ---------------------------------------------------------
					; All OK, enumerate this resource...
					; ---------------------------------------------------------

					For loop = 0 To count - 1
					
						*temp.NETRESOURCE = *mem + (loop * SizeOf (NETRESOURCE))
			
						iterate = #False ; Used at end of loop to enumerate this resource...
						
						; -------------------------------------------------------------
						; Read available strings for resource...
						; -------------------------------------------------------------
		
						If *temp\lpLocalName <> #Null
							Debug in$ + "Local resource name: " + PeekS (*temp\lpLocalName)
						EndIf
						
						If *temp\lpRemoteName <> #Null
						
							name$ = PeekS (*temp\lpRemoteName)
							
							If Left (name$, 2) = "\\"
								name$ = Mid (name$, 3)
							EndIf
							
							info$ = in$ + "Remote resource name: " + name$

							If *temp\dwDisplayType = #RESOURCEDISPLAYTYPE_SERVER
								ip$ = GetIP (name$)
								If ip$ <> ""
									info$ = info$ + " (" + ip$ + ")"
								EndIf
							EndIf

							Debug info$
							
						EndIf
						
						If *temp\lpProvider <> #Null
							Debug in$ + "Network resource provider: " + PeekS (*temp\lpProvider)
						EndIf
			
						If *temp\lpComment <> #Null
							comment$ = PeekS (*temp\lpComment)
							If comment$ = ""
								comment$ = "[No comment set]"
							EndIf
							Debug in$ + "Comment: " + comment$
						EndIf
						
						; -------------------------------------------------------------
						; Get scope of resource...
						; -------------------------------------------------------------
		
						Select *temp\dwScope
			
							Case #RESOURCE_CONNECTED
							
								Debug in$ + "Scope: Currently connected resource"
			
							Case #RESOURCE_GLOBALNET
			
								Debug in$ + "Scope: Network resource"
			
								; NOTE: dwUsage is only valid for #RESOURCE_GLOBALNET...
								
								If *temp\dwUsage And #RESOURCEUSAGE_CONNECTABLE
									Debug in$ + "Usage: Connectable resource"
								EndIf
			
								If *temp\dwUsage And #RESOURCEUSAGE_CONTAINER
								
									Debug in$ + "Usage: Container resource"
									
									If *temp\dwType <> #RESOURCETYPE_DISK
										iterate = #True ; Can iterate through this resource...
									EndIf
									
								EndIf

							Case #RESOURCE_REMEMBERED
							
								Debug in$ + "Scope: Persistent resource"
			
						EndSelect
			
						; -------------------------------------------------------------
						; Get type of resource...
						; -------------------------------------------------------------
		
						Select *temp\dwType
						
							Case #RESOURCETYPE_ANY
								Debug in$ + "Share type: Undefined (probably a container)"
							
							Case #RESOURCETYPE_DISK
							
								Debug in$ + "Share type: Disk"
		
								; Get disk size/space...
								
								If *temp\lpRemoteName <> #Null
								
									SetErrorMode_ (#SEM_FAILCRITICALERRORS)
					
									If GetDiskFreeSpaceEx_ (*temp\lpRemoteName, @ignored.q, @totalbytes.q, @freebytes.q)
									
										total = totalbytes / 1024 / 1024 / 1024
										free = freebytes / 1024 / 1024 / 1024
									
										Debug in$ + "Share size: " + StrU (total, #PB_Quad) + " GB"
										Debug in$ + "Free space: " + StrU (free, #PB_Quad) + " GB"
									
									Else
									
										Debug "Couldn't read disk size/space"
								
									EndIf
		
								SetErrorMode_ (0)
		
								EndIf
														
							Case #RESOURCETYPE_PRINT
								Debug in$ + "Share type: Printer"
							
						EndSelect
							
						; -------------------------------------------------------------
						; How the resource is displayed in a network browser GUI...
						; -------------------------------------------------------------
		
						Select *temp\dwDisplayType
							Case #RESOURCEDISPLAYTYPE_DOMAIN
								Debug in$ + "Displayed as: Domain"
							Case #RESOURCEDISPLAYTYPE_GENERIC
								Debug in$ + "Displayed as: Generic"
							Case #RESOURCEDISPLAYTYPE_SERVER
								Debug in$ + "Displayed as: Server"
							Case #RESOURCEDISPLAYTYPE_SHARE
								Debug in$ + "Displayed as: Share"
							Default
								Debug in$ + "Displayed as: Unknown (probably root node)"
						EndSelect
						
						Debug ""
		
						; -------------------------------------------------------------
						; Try to enumerate this resource (recursive function call)...
						; -------------------------------------------------------------
		
						If iterate
							indent = indent + 1
							ShowNetworkInfo (*temp, indent)
							indent = indent - 1
						EndIf
						
					Next
				
				Case #ERROR_NO_MORE_ITEMS
				
					; ---------------------------------------------------------
					; Can't enumerate within this resource...
					; ---------------------------------------------------------

					Debug in$ + "No items to enumerate in this resource"
					Debug ""
					
			EndSelect
		
			FreeMemory (*mem)
			WNetCloseEnum_ (enum)

		Case #ERROR_NOT_CONTAINER

			Debug in$ + "The specified resource is not a container"
			Debug ""

		Case #ERROR_INVALID_PARAMETER

			Debug in$ + "WNetOpenEnum received an invalid dwScope or dwType parameter"
			Debug ""

		Case #ERROR_NO_NETWORK

			Debug in$ + "No network connected to resource being enumerated"
			Debug ""

		Case #ERROR_EXTENDED_ERROR

			Debug in$ + "Extended error information available:"

			; Untested -- haven't run into this and don't know how to test! Should work, though...
			
			*errorbuffer = AllocateMemory (1024)
			*providerbuffer = AllocateMemory (1024)
			
			If WNetGetLastError_ (@neterror, *errorbuffer, 1024, *providerbuffer, 1024) = #NO_ERROR
				Debug PeekS (*providerbuffer) + " reports: " + PeekS (*errorbuffer)
			EndIf

			Debug ""

		Default
		
			Debug in$ + "Unexpected error on opening resource. (Eg. May not support enumeration.)"
			
			; This is (ironically) expected sometimes! Eg. "NetDrive Network" doesn't
			; support enumeration and reports "The request is not supported" when
			; GetLastError () is called...

			Debug ""

		EndSelect
		
EndProcedure

Debug ""
Debug "Scanning LAN -- this may take some time!"
Debug ""

ShowNetworkInfo ()

James Boyd
http://www.hi-toro.com/
Death to the Pixies!
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: List resources on local area network

Post by rsts »

Very nice.

Testing it caused me to notice a misconfiguration in my network as a result of a recent system change :D

Thanks for sharing.

cheers
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

Cool!

On a similar topic (still trying to resolve the public vs LAN IP for the client running this code), this lists the multiple IP addresses your PC may have, eg. LAN address, public IP address, etc.

Note that you'll only see more than one IP in the Debug Output window if you have more than one network connection, eg. a LAN connection and direct internet connection.

Unfortunately, I still haven't found a way to automatically determine which is the local IP (without hard-coding value checks)...

Code: Select all


; TURN DEBUGGER ON TO SEE OUTPUT!

Procedure GetIPs (List ip_list.s ())

	; Get local computer name...
	
	computer$ = Space (#MAX_COMPUTERNAME_LENGTH + 1)
	size = Len (computer$)
	
	If GetComputerName_ (@computer$, @size)

		wsaversion.w
		
		; Poke WSA major/minor version required into this word...
		
		PokeB (@wsaversion, 1)
		PokeB (@wsaversion + 1, 1)
		
		If WSAStartup_ (wsaversion, wsa.WSAData) = #NOERROR ; Try to access Windows sockets stuff...
		
			*host.HOSTENT = gethostbyname_ (computer$) ; Get host information for named computer...
			
			If *host <> #Null

				; Create own copy of far pointer to IP list (MSDN says not to modify the
				; contents of a HOSTENT structure)...
				
				*ip_list = *host\h_addr_list
				
				; Only supporting TCP/IP v4 here...

				If *host\h_addrtype = #AF_INET
				
					; Flag for exiting loop...
					
					no_more_ips = #False
					
					Repeat
	
						*ip_list_addr = PeekL (*ip_list) ; Pointer to array of IPs
					
						If *ip_list_addr <> #Null ; Pointer will be Null at end of array
						
							ip = PeekL (*ip_list_addr) ; Get IP address as 32-bit integer
							dotted$ = PeekS (inet_ntoa_ (ip)) ; Convert to "255.255.255.255" format
							
							AddElement (ip_list ())
							ip_list () = dotted$
							
							*ip_list = *ip_list + *host\h_length ; Get next IP address for this computer
							
						Else
							no_more_ips = #True
						EndIf
						
					Until no_more_ips

				EndIf
								
			EndIf
			
			WSACleanup_ () ; Close Windows sockets stuff...
		
		EndIf
	
	EndIf

EndProcedure

; Test...

NewList ips.s ()

GetIPs (ips ()) ; Pass a list to receive all IPs...

ResetList (ips ())
While NextElement (ips ())
	Debug ips ()
Wend
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Re: List resources on local area network

Post by Rook Zimbabwe »

I get an error in 4.3 on line 25... weather or not I have inline ASM activated (and weather or not I have restarted the compailer after making sure!)

"Can't use an ASM keyword for an affectation."

OK I just used Find & Replace to change all instances of in$ to "INP$" and that worked!

NICE!!! :mrgreen:
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Re: List resources on local area network

Post by Rook Zimbabwe »

I tried to modify this to display in a TREE gadget... my progrma just sits there and nothing is drawn...

What did I do wrong?

Code: Select all

; IP RESOURCE LISTER by Hi-Toro
; Attempted Treeview by Rook Zimbabwe - FAIL!
;
Enumeration
  #Window_IP
EndEnumeration

Enumeration
  #Text_STATUS
  #Text_3
  #Text_2
  #Text_SUBNET
  #Text_IP
  #Tree_0
EndEnumeration

Structure VisualDesignerGadgets
  Gadget.l
  EventFunction.l
EndStructure

Global NewList EventProcedures.VisualDesignerGadgets()

;-
Procedure.s GetIP (ComputerName.s)
   ; By Flype! (Just reformatted to my preference.)
   If ComputerName
      If WSAStartup_ ((1<<8|1), wsa.WSADATA) = #NOERROR
         *host.HOSTENT = gethostbyname_ (ComputerName)
         WSACleanup_ ()
         If *host
            ProcedureReturn PeekS (inet_ntoa_ (PeekL (PeekL (*host\h_addr_list))))
         EndIf
      EndIf
   EndIf
EndProcedure


; -----------------------------------------------------------------------------
; Enumerate LAN resources...
; -----------------------------------------------------------------------------

Procedure ShowNetworkInfo (*resource.NETRESOURCE = #Null, indent = 0)

   ; Indent string for AddGadgetItem (#Tree_0, -1,ging recursive function...


   chunk = 131050;262144 ; 4 times the M$-suggested amount (in 1992-1996)...
   
   openresult = WNetOpenEnum_ (#RESOURCE_GLOBALNET, #RESOURCETYPE_ANY, 0, *resource, @enum)
   
   Select openresult
   
      Case #NO_ERROR

         size = chunk
         
         ; Try to enumerate resources. In the unlikely event that the buffer is too small,
         ; add another 'chunk' of memory until OK...
         
         ; Probably won't be relevant except for massive business networks anyway...
         
         Repeat
   
            count = $FFFFFFFF
   
            *mem = ReAllocateMemory (*mem, size)
   
            enumresult = WNetEnumResource_ (enum, @count, *mem, @size)
            
            If enumresult = #ERROR_MORE_DATA
               size = size + chunk
            EndIf
            
         Until enumresult <> #ERROR_MORE_DATA
         
         Select enumresult
         
            Case #NO_ERROR
   
               ; ---------------------------------------------------------
               ; All OK, enumerate this resource...
               ; ---------------------------------------------------------

               For LOOP = 0 To count - 1
               
                  *temp.NETRESOURCE = *mem + (LOOP * SizeOf (NETRESOURCE))
         
                  iterate = #False ; Used at end of loop to enumerate this resource...
                  
                  ; -------------------------------------------------------------
                  ; Read available strings for resource...
                  ; -------------------------------------------------------------
      
                  If *temp\lpLocalName <> #Null
                     AddGadgetItem (#Tree_0, -1,  "Local resource name: " + PeekS (*temp\lpLocalName), 0, 0) 
                  EndIf
                  
                  If *temp\lpRemoteName <> #Null
                  
                     name$ = PeekS (*temp\lpRemoteName)
                     
                     If Left (name$, 2) = "\\"
                        name$ = Mid (name$, 3)
                     EndIf
                     
                     info$ =  "Remote resource name: " + name$

                     If *temp\dwDisplayType = #RESOURCEDISPLAYTYPE_SERVER
                        ip$ = GetIP (name$)
                        If ip$ <> ""
                           info$ = info$ + " (" + ip$ + ")"
                        EndIf
                     EndIf

                     AddGadgetItem (#Tree_0, -1, info$ , 0, 0)
                     
                  EndIf
                  
                  If *temp\lpProvider <> #Null
                     AddGadgetItem (#Tree_0, -1,  "Network resource provider: " + PeekS (*temp\lpProvider), 0, 0)
                  EndIf
         
                  If *temp\lpComment <> #Null
                     comment$ = PeekS (*temp\lpComment)
                     If comment$ = ""
                        comment$ = "[No comment set]"
                     EndIf
                     AddGadgetItem (#Tree_0, -1,  "Comment: " + comment$ , 0, 1)
                  EndIf
                  
                  ; -------------------------------------------------------------
                  ; Get scope of resource...
                  ; -------------------------------------------------------------
      
                  Select *temp\dwScope
         
                     Case #RESOURCE_CONNECTED
                     
                        AddGadgetItem (#Tree_0, -1,  "Scope: Currently connected resource", 0, 0)
         
                     Case #RESOURCE_GLOBALNET
         
                        AddGadgetItem (#Tree_0, -1,  "Scope: Network resource", 0, 1)
         
                        ; NOTE: dwUsage is only valid for #RESOURCE_GLOBALNET...
                        
                        If *temp\dwUsage And #RESOURCEUSAGE_CONNECTABLE
                           AddGadgetItem (#Tree_0, -1,  "Usage: Connectable resource", 0, 1)
                        EndIf
         
                        If *temp\dwUsage And #RESOURCEUSAGE_CONTAINER
                        
                           AddGadgetItem (#Tree_0, -1,  "Usage: Container resource", 0, 1)
                           
                           If *temp\dwType <> #RESOURCETYPE_DISK
                              iterate = #True ; Can iterate through this resource...
                           EndIf
                           
                        EndIf

                     Case #RESOURCE_REMEMBERED
                     
                        AddGadgetItem (#Tree_0, -1,  "Scope: Persistent resource", 0, 2)
         
                  EndSelect
         
                  ; -------------------------------------------------------------
                  ; Get type of resource...
                  ; -------------------------------------------------------------
      
                  Select *temp\dwType
                  
                     Case #RESOURCETYPE_ANY
                        AddGadgetItem (#Tree_0, -1,  "Share type: Undefined (probably a container)", 0, 0)
                     
                     Case #RESOURCETYPE_DISK
                     
                        AddGadgetItem (#Tree_0, -1,  "Share type: Disk", 0, 0)
      
                        ; Get disk size/space...
                        
                        If *temp\lpRemoteName <> #Null
                        
                           SetErrorMode_ (#SEM_FAILCRITICALERRORS)
               
                           If GetDiskFreeSpaceEx_ (*temp\lpRemoteName, @ignored.q, @totalbytes.q, @freebytes.q)
                           
                              total = totalbytes / 1024 / 1024 / 1024
                              free = freebytes / 1024 / 1024 / 1024
                           
                              AddGadgetItem (#Tree_0, -1,  "Share size: " + StrU (total, #PB_Quad) + " GB", 0, 1)
                              AddGadgetItem (#Tree_0, -1,  "Free space: " + StrU (free, #PB_Quad) + " GB", 0, 1)
                           
                           Else
                           
                              AddGadgetItem (#Tree_0, -1, "Couldn't read disk size/space", 0, 1)
                        
                           EndIf
      
                        SetErrorMode_ (0)
      
                        EndIf
                                          
                     Case #RESOURCETYPE_PRINT
                        AddGadgetItem (#Tree_0, -1,  "Share type: Printer", 0, 0)
                     
                  EndSelect
                     
                  ; -------------------------------------------------------------
                  ; How the resource is displayed in a network browser GUI...
                  ; -------------------------------------------------------------
      
                  Select *temp\dwDisplayType
                     Case #RESOURCEDISPLAYTYPE_DOMAIN
                        AddGadgetItem (#Tree_0, -1,  "Displayed as: Domain", 0, 0)
                     Case #RESOURCEDISPLAYTYPE_GENERIC
                        AddGadgetItem (#Tree_0, -1,  "Displayed as: Generic", 0, 0)
                     Case #RESOURCEDISPLAYTYPE_SERVER
                        AddGadgetItem (#Tree_0, -1,  "Displayed as: Server", 0, 0)
                     Case #RESOURCEDISPLAYTYPE_SHARE
                        AddGadgetItem (#Tree_0, -1,  "Displayed as: Share", 0, 0)
                     Default
                        AddGadgetItem (#Tree_0, -1,  "Displayed as: Unknown (probably root node)", 0, 0)
                  EndSelect
                  
                  ;AddGadgetItem (#Tree_0, -1, ""
      
                  ; -------------------------------------------------------------
                  ; Try to enumerate this resource (recursive function call)...
                  ; -------------------------------------------------------------
      
                  If iterate
                     indent = indent + 1
                     ShowNetworkInfo (*temp, indent)
                     indent = indent - 1
                  EndIf
                  
               Next
            
            Case #ERROR_NO_MORE_ITEMS
            
               ; ---------------------------------------------------------
               ; Can't enumerate within this resource...
               ; ---------------------------------------------------------

               AddGadgetItem (#Tree_0, -1,  "No items to enumerate in this resource", 0, 2)
               ;AddGadgetItem (#Tree_0, -1, ""
               
         EndSelect
      
         FreeMemory (*mem)
         WNetCloseEnum_ (enum)

      Case #ERROR_NOT_CONTAINER

         AddGadgetItem (#Tree_0, -1,  "The specified resource is not a container", 0, 2)
         ;AddGadgetItem (#Tree_0, -1, ""

      Case #ERROR_INVALID_PARAMETER

         AddGadgetItem (#Tree_0, -1,  "WNetOpenEnum received an invalid dwScope or dwType parameter", 0, 2)
        ; AddGadgetItem (#Tree_0, -1, ""

      Case #ERROR_NO_NETWORK

         AddGadgetItem (#Tree_0, -1,  "No network connected to resource being enumerated", 0, 2)
        ; AddGadgetItem (#Tree_0, -1, ""

      Case #ERROR_EXTENDED_ERROR

         AddGadgetItem (#Tree_0, -1,  "Extended error information available:", 0, 2)

         ; Untested -- haven't run into this and don't know how to test! Should work, though...
         
         *errorbuffer = AllocateMemory (1024)
         *providerbuffer = AllocateMemory (1024)
         
         If WNetGetLastError_ (@neterror, *errorbuffer, 1024, *providerbuffer, 1024) = #NO_ERROR
            AddGadgetItem (#Tree_0, -1, PeekS (*providerbuffer) + " reports: " + PeekS (*errorbuffer), 0, 0)
         EndIf

        ; AddGadgetItem (#Tree_0, -1, ""

      Default
      
         AddGadgetItem (#Tree_0, -1,  "Unexpected error on opening resource. (Eg. May not support enumeration.)", 0, 0)
         
         ; This is (ironically) expected sometimes! Eg. "NetDrive Network" doesn't
         ; support enumeration and reports "The request is not supported" when
         ; GetLastError () is called...

        ; AddGadgetItem (#Tree_0, -1, ""

      EndSelect
      
EndProcedure
;-

Procedure Tree_0_Event(Window, Event, Gadget, Type)
 ; AddGadgetItem (#Tree_0, -1, "#Tree_0"
EndProcedure
;-
Procedure RegisterGadgetEvent(Gadget, *Function)
  
  If IsGadget(Gadget)
    AddElement(EventProcedures())
    EventProcedures()\Gadget        = Gadget
    EventProcedures()\EventFunction = *Function
  EndIf
  
EndProcedure

Procedure CallEventFunction(Window, Event, Gadget, Type)
  
  ForEach EventProcedures()
    If EventProcedures()\Gadget = Gadget
      CallFunctionFast(EventProcedures()\EventFunction, Window, Event, Gadget, Type)
      LastElement(EventProcedures())
    EndIf
  Next
  
EndProcedure
;-
Procedure Open_Window_IP()
  
  If OpenWindow(#Window_IP, 5, 5, 570, 359, "IPzone 1.0",  #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
    ;If CreateGadgetList(WindowID(#Window_IP)) ; REMmed out for 4.3+
      TreeGadget(#Tree_0, 10, 40, 545, 265)
      RegisterGadgetEvent(#Tree_0, @Tree_0_Event())
      
      TextGadget(#Text_IP, 10, 20, 175, 15, "", #PB_Text_Center | #PB_Text_Border)
      TextGadget(#Text_SUBNET, 210, 20, 160, 15, "", #PB_Text_Center | #PB_Text_Border)
      TextGadget(#Text_STATUS, 10, 330, 545, 20, "", #PB_Text_Center | #PB_Text_Border)
      TextGadget(#Text_2, 15, 5, 25, 10, "IP")
      TextGadget(#Text_3, 210, 0, 75, 15, "SUBNET")
      
    ;EndIf ; Also REMmed out for 4.3+
  EndIf
EndProcedure

Open_Window_IP()


SetGadgetText(#Text_STATUS, "Scanning LAN -- this may take some time!")

ShowNetworkInfo ()



SetGadgetText(#Text_STATUS, "FINISHED...")
Repeat
  
  Event  = WaitWindowEvent()
  Gadget = EventGadget()
  Type   = EventType()
  Window = EventWindow()
  
  Select Event
    Case #PB_Event_Gadget
      CallEventFunction(Window, Event, Gadget, Type)
      
  EndSelect
  
Until Event = #PB_Event_CloseWindow

End

(I just wanted to make it look fancy!) :shock:

{{EDIT}} OK it works... The office has an extended VPN which has shown up therough this...
Now I need to format this ia bit better!

Help that way would be appreciated!!!

Took 3 mins to complete on my system... CODE UPDATED
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

Nice try, Rook! I suggest adding "indent" (a variable in the code) to all of your AddGadgetItem flags, which almost looks right in terms of listing child resources. (Still needs some tweaking.)

I'd also recommend running the procedure in a thread and updating your window's events while it runs -- this will avoid locking the GUI. You might have to add each item (and its indent) to a list rather than trying to create the gadget items in a thread, just doing it all once the thread exits.
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

This looks right (note you only get one item at the start -- the root network node):

EDIT: Updated to run in a thread so the GUI remains responsive.

Code: Select all

; IP RESOURCE LISTER by Hi-Toro
; Attempted Treeview by Rook Zimbabwe - FAIL!
;
Enumeration
  #Window_IP
EndEnumeration

Enumeration
  #Text_STATUS
  #Text_3
  #Text_2
  #Text_SUBNET
  #Text_IP
  #Tree_0
EndEnumeration

Structure VisualDesignerGadgets
  Gadget.l
  EventFunction.l
EndStructure

Global NewList EventProcedures.VisualDesignerGadgets()

;-
Procedure.s GetIP (ComputerName.s)
   ; By Flype! (Just reformatted to my preference.)
   If ComputerName
      If WSAStartup_ ((1<<8|1), wsa.WSADATA) = #NOERROR
         *host.HOSTENT = gethostbyname_ (ComputerName)
         WSACleanup_ ()
         If *host
            ProcedureReturn PeekS (inet_ntoa_ (PeekL (PeekL (*host\h_addr_list))))
         EndIf
      EndIf
   EndIf
EndProcedure


; -----------------------------------------------------------------------------
; Enumerate LAN resources...
; -----------------------------------------------------------------------------

Structure ResourceIndent
	*resource.NETRESOURCE
	indent.l
EndStructure

Structure GadgetInfo
	gtext$
	indent.l
EndStructure

Global NewList testlist.GadgetInfo ()

Procedure ShowNetworkInfo (*ri.ResourceIndent)

	*resource.NETRESOURCE = *ri\resource
	indent = *ri\indent
	If indent < 1
		indent = 1
	EndIf
		
   ; Indent string for AddGadgetItem (#Tree_0, -1,ging recursive function...


   chunk = 131050;262144 ; 4 times the M$-suggested amount (in 1992-1996)...
   
   openresult = WNetOpenEnum_ (#RESOURCE_GLOBALNET, #RESOURCETYPE_ANY, 0, *resource, @enum)
   
   Select openresult
   
      Case #NO_ERROR

;			Debug "No open error"
			
         size = chunk
         
         ; Try to enumerate resources. In the unlikely event that the buffer is too small,
         ; add another 'chunk' of memory until OK...
         
         ; Probably won't be relevant except for massive business networks anyway...
         
         Repeat
   
            count = $FFFFFFFF
   
            *mem = ReAllocateMemory (*mem, size)
   
            enumresult = WNetEnumResource_ (enum, @count, *mem, @size)
            
            If enumresult = #ERROR_MORE_DATA
               size = size + chunk
            EndIf
            
         Until enumresult <> #ERROR_MORE_DATA
         
         Select enumresult
         
            Case #NO_ERROR
   
;				Debug "No enum error"
				
               ; ---------------------------------------------------------
               ; All OK, enumerate this resource...
               ; ---------------------------------------------------------

               For LOOP = 0 To count - 1
               
                  *temp.NETRESOURCE = *mem + (LOOP * SizeOf (NETRESOURCE))

                  iterate = #False ; Used at end of loop to enumerate this resource...
                  
                  ; -------------------------------------------------------------
                  ; Read available strings for resource...
                  ; -------------------------------------------------------------
      
                  If *temp\lpLocalName <> #Null
                  
                  	AddElement (testlist ())
                  	testlist ()\gtext$ = PeekS (*temp\lpLocalName)
                  	testlist ()\indent = indent
                  	
                  EndIf
                  
                  If *temp\lpRemoteName <> #Null
                  
                     name$ = PeekS (*temp\lpRemoteName)
                     
                     If Left (name$, 2) = "\\"
                        name$ = Mid (name$, 3)
                     EndIf
                     
                     info$ =  "Remote resource name: " + name$

                     If *temp\dwDisplayType = #RESOURCEDISPLAYTYPE_SERVER
                        ip$ = GetIP (name$)
                        If ip$ <> ""
                           info$ = info$ + " (" + ip$ + ")"
                        EndIf
                     EndIf
                  

                  	AddElement (testlist ())
                  	testlist ()\gtext$ = info$
                  	testlist ()\indent = indent
				

                  EndIf

                  If *temp\lpProvider <> #Null
				
                  	AddElement (testlist ())
                  	testlist ()\gtext$ = PeekS (*temp\lpProvider)
                  	testlist ()\indent = indent
				
                  EndIf
         
                  If *temp\lpComment <> #Null
                     comment$ = PeekS (*temp\lpComment)
                     If comment$ = ""
                        comment$ = "[No comment set]"
                     EndIf
				
                  	AddElement (testlist ())
                  	testlist ()\gtext$ = comment$
                  	testlist ()\indent = indent
				
                  EndIf
                  
                  ; -------------------------------------------------------------
                  ; Get scope of resource...
                  ; -------------------------------------------------------------
      
                  Select *temp\dwScope
         
                     Case #RESOURCE_CONNECTED
                     
				
                  	AddElement (testlist ())
                  	testlist ()\gtext$ = "Scope: Currently connected resource"
                  	testlist ()\indent = indent
				
       
                     Case #RESOURCE_GLOBALNET
         
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Scope: Network resource"
                  	testlist ()\indent = indent
				
         
                        ; NOTE: dwUsage is only valid for #RESOURCE_GLOBALNET...
                        
                        If *temp\dwUsage And #RESOURCEUSAGE_CONNECTABLE
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Usage: Connectable resource"
                  	testlist ()\indent = indent
				
                        EndIf
         
                        If *temp\dwUsage And #RESOURCEUSAGE_CONTAINER
                        
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Usage: Container resource"
                  	testlist ()\indent = indent
				
                           
                           If *temp\dwType <> #RESOURCETYPE_DISK
                              iterate = #True ; Can iterate through this resource...
                           EndIf
                           
                        EndIf

                     Case #RESOURCE_REMEMBERED
                     
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Scope: Persistent resource"
                  	testlist ()\indent = indent
				
         
                  EndSelect
         
                  ; -------------------------------------------------------------
                  ; Get type of resource...
                  ; -------------------------------------------------------------
      
                  Select *temp\dwType
                  
                     Case #RESOURCETYPE_ANY
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Share type: Undefined (probably a container)"
                  	testlist ()\indent = indent
				
                     
                     Case #RESOURCETYPE_DISK
                     
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Share type: Disk"
                  	testlist ()\indent = indent
				
      
                        ; Get disk size/space...
                        
                        If *temp\lpRemoteName <> #Null
                        
                           SetErrorMode_ (#SEM_FAILCRITICALERRORS)
               
                           If GetDiskFreeSpaceEx_ (*temp\lpRemoteName, @ignored.q, @totalbytes.q, @freebytes.q)
                           
                              total = totalbytes / 1024 / 1024 / 1024
                              free = freebytes / 1024 / 1024 / 1024
                           
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Share size: " + StrU (total, #PB_Quad) + " GB"
                  	testlist ()\indent = indent
				
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Free space: " + StrU (free, #PB_Quad) + " GB"
                  	testlist ()\indent = indent
				
                           
                           Else
                           
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Couldn't read disk size/space"
                  	testlist ()\indent = indent
				
                        
                           EndIf
      
                        SetErrorMode_ (0)
      
                        EndIf
                                          
                     Case #RESOURCETYPE_PRINT
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Share type: Printer"
                  	testlist ()\indent = indent
				
                     
                  EndSelect
                     
                  ; -------------------------------------------------------------
                  ; How the resource is displayed in a network browser GUI...
                  ; -------------------------------------------------------------
      
                  Select *temp\dwDisplayType
                     Case #RESOURCEDISPLAYTYPE_DOMAIN
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Displayed as: Domain"
                  	testlist ()\indent = indent
				
                     Case #RESOURCEDISPLAYTYPE_GENERIC
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Displayed as: Generic"
                  	testlist ()\indent = indent
				
                     Case #RESOURCEDISPLAYTYPE_SERVER
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Displayed as: Server"
                  	testlist ()\indent = indent
				
                     Case #RESOURCEDISPLAYTYPE_SHARE
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Displayed as: Share"
                  	testlist ()\indent = indent
				
                     Default
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Displayed as: Unknown (probably root node)"
                  	testlist ()\indent = indent
				
                  EndSelect
                  
      
                  ; -------------------------------------------------------------
                  ; Try to enumerate this resource (recursive function call)...
                  ; -------------------------------------------------------------
      
                  If iterate
                  
                  		name$ = ""
	                  If *temp\lpRemoteName <> #Null
	                  
	                     name$ = PeekS (*temp\lpRemoteName)
	                     
	                     If Left (name$, 2) = "\\"
	                        name$ = Mid (name$, 3)
	                     EndIf
	                     
	                 Else
	                 	name$ = "Resource "
	                 EndIf
                 
				
                  	AddElement (testlist ())
                  	testlist ()\gtext$ = "Open to display contents of " + name$
                  	testlist ()\indent = indent
				

                     indent = indent + 1

					res.ResourceIndent
					res\resource = *temp
					res\indent = indent

                     ShowNetworkInfo (@res)
					                     
                     indent = indent - 1
                     
                  EndIf
                  
               Next
            
            Case #ERROR_NO_MORE_ITEMS
            
               ; ---------------------------------------------------------
               ; Can't enumerate within this resource...
               ; ---------------------------------------------------------

				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "No items to enumerate in this resource"
                  	testlist ()\indent = indent
               
         EndSelect
      
         FreeMemory (*mem)
         WNetCloseEnum_ (enum)

      Case #ERROR_NOT_CONTAINER

				
                  	AddElement (testlist ())
                  	testlist ()\gtext$ = "The specified resource is not a container"
                  	testlist ()\indent = indent
				

      Case #ERROR_INVALID_PARAMETER

				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "WNetOpenEnum received an invalid dwScope or dwType parameter"
                  	testlist ()\indent = indent
				

      Case #ERROR_NO_NETWORK

				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "No network connected to resource being enumerated"
                  	testlist ()\indent = indent
				

      Case #ERROR_EXTENDED_ERROR

				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Extended error information available:"
                  	testlist ()\indent = indent
				
         ; Untested -- haven't run into this and don't know how to test! Should work, though...
         
         *errorbuffer = AllocateMemory (1024)
         *providerbuffer = AllocateMemory (1024)
         
         If WNetGetLastError_ (@neterror, *errorbuffer, 1024, *providerbuffer, 1024) = #NO_ERROR
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = PeekS (*providerbuffer) + " reports: " + PeekS (*errorbuffer)
                  	testlist ()\indent = indent
				
         EndIf

      Default
      
				
                   	AddElement (testlist ())
                  	testlist ()\gtext$ = "Unexpected error on opening resource. (Eg. May not support enumeration.)"
                  	testlist ()\indent = indent
				
         ; This is (ironically) expected sometimes! Eg. "NetDrive Network" doesn't
         ; support enumeration and reports "The request is not supported" when
         ; GetLastError () is called...

      EndSelect
      
;      Debug "Enum done..."
      
EndProcedure
;-

Procedure Tree_0_Event(Window, Event, Gadget, Type)
; AddGadgetItem (#Tree_0, -1, "#Tree_0"
EndProcedure
;-
Procedure RegisterGadgetEvent(Gadget, *Function)
  
  If IsGadget(Gadget)
    AddElement(EventProcedures())
    EventProcedures()\Gadget        = Gadget
    EventProcedures()\EventFunction = *Function
  EndIf
  
EndProcedure

Procedure CallEventFunction(Window, Event, Gadget, Type)
  
  ForEach EventProcedures()
    If EventProcedures()\Gadget = Gadget
      CallFunctionFast(EventProcedures()\EventFunction, Window, Event, Gadget, Type)
      LastElement(EventProcedures())
    EndIf
  Next
  
EndProcedure
;-
Procedure Open_Window_IP()
  
  If OpenWindow(#Window_IP, 5, 5, 570, 359, "IPzone 1.0",  #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
      TreeGadget(#Tree_0, 10, 40, 545, 265)
      RegisterGadgetEvent(#Tree_0, @Tree_0_Event())
      
      TextGadget(#Text_IP, 10, 20, 175, 15, "", #PB_Text_Center | #PB_Text_Border)
      TextGadget(#Text_SUBNET, 210, 20, 160, 15, "", #PB_Text_Center | #PB_Text_Border)
      TextGadget(#Text_STATUS, 10, 330, 545, 20, "", #PB_Text_Center | #PB_Text_Border)
      TextGadget(#Text_2, 15, 5, 25, 10, "IP")
      TextGadget(#Text_3, 210, 0, 75, 15, "SUBNET")
      
  EndIf
EndProcedure

Open_Window_IP()

SetGadgetText(#Text_STATUS, "Scanning LAN -- this may take some time!")

res.ResourceIndent
res\resource = #Null
res\indent = 1

thread = CreateThread (@ShowNetworkInfo (), @res)

SetTimer_ (WindowID (#Window_IP), 1, 500, #Null)

Repeat
  
  Event  = WaitWindowEvent()
  Gadget = EventGadget()
  Type   = EventType()
  Window = EventWindow()
  
  Select Event
    Case #PB_Event_Gadget
      CallEventFunction(Window, Event, Gadget, Type)
    Case #WM_TIMER
    	If threaddone = 0 ; HACK: See KillTimer comment below!
	    	If IsThread (thread) = 0
				ResetList (testlist ())
				While NextElement (testlist ())
					AddGadgetItem (#Tree_0, -1,  testlist ()\gtext$, 0, testlist ()\indent)
				Wend
	    		Debug "Thread finished!"
				SetGadgetText(#Text_STATUS, "FINISHED...")
	    		KillTimer_ (WindowID (#Window_IP), 1) ; GAH! WHY DOESN'T THIS STOP TIMER MESSAGES?!!!
	    		threaddone = 1
	    	Else
	    		info$ = "Scanning LAN -- this may take some time!"
	    		switch = 1 - switch
	    		If switch
		    		info$ = "* " + info$ + " *"
	    		EndIf
		    	SetGadgetText(#Text_STATUS, info$)
	    	EndIf
	    EndIf
  EndSelect
  
Until Event = #PB_Event_CloseWindow

SetGadgetText(#Text_STATUS, "Waiting for thread to finish. Click Close [X] again to force quit...")

Repeat
	If WaitWindowEvent () = #PB_Event_CloseWindow
		End
	EndIf
Until IsThread (thread) = 0

End
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

BTW I just resolved the massive delay here -- turn on Network Discovery if running on Vista/7. I had to reboot before it worked. Also, it silently turns itself off right away if certain services aren't running, so go out and check it again after turning it on! See the "What is network discovery?" help link, in the Custom section (even if not using a Custom setting) when turning it on.

(If you're on XP or lower, try turning off "automatic search for network printers and folders". See: http://support.microsoft.com/kb/320138 for details.)
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

Just continuing to document this stuff here for future reference (mine or anyone else's!). This is all Win32 only, and refers only to IPv4...

This retrieves IP addresses and subnet masks for all local network adapters, in theory. Works here. The subnet test is part of me trying to resolve the original problem I had (see first post), but I think I've just found a better way, and will post if I get it working...

Code: Select all


; TURN DEBUGGER ON TO SEE OUTPUT!

; Use command line -> ipconfig to see subnet mask for each network adapter on your system...

subnet$ = "255.255.255.0" ; Enter subnet mask to test here!

Procedure.l IntFromAddress (ip$)
	ProcedureReturn inet_addr_ (@ip$)
EndProcedure

Procedure.s AddressFromInt (ip.l)
	ProcedureReturn PeekS (inet_ntoa_ (ip))
EndProcedure

Structure MIB_IPADDRROW
	dwAddr.l
	dwIndex.l
	dwMask.l
	dwBCastAddr.l
	dwReasmSize.l
	unused1.w
	wType.w
EndStructure

Structure MIB_IPADDRTABLE
	dwNumEntries.l
	*ips.MIB_IPADDRROW
EndStructure

#MIB_IPADDR_PRIMARY = $0001
#MIB_IPADDR_DYNAMIC = $0004
#MIB_IPADDR_DISCONNECTED = $0008
#MIB_IPADDR_DELETED = $0040
#MIB_IPADDR_TRANSIENT = $0080

tablesize = SizeOf (MIB_IPADDRTABLE)
*table.MIB_IPADDRTABLE = AllocateMemory (tablesize)

valid = #False

Repeat

	Select GetIpAddrTable_ (*table, @tablesize, #True)
		
		Case #NO_ERROR
			valid = #True

		Case #ERROR_INSUFFICIENT_BUFFER
		
			*table = ReAllocateMemory (*table, tablesize)

		Case #ERROR_INVALID_PARAMETER
			Debug "Param"

		Case #ERROR_NOT_SUPPORTED
			Debug "Not supported"

		Default
			Debug "Call GetError!"
		
	EndSelect

Until valid

*ipinfo.MIB_IPADDRROW = @*table\ips

For loop = 0 To *table\dwNumEntries - 1

	interfaceindex = *ipinfo\dwIndex

	If interfaceindex > 0

		Debug "Interface #" + Str (interfaceindex)
		
		ip = *ipinfo\dwAddr
		add$ = PeekS (inet_ntoa_ (ip))
		Debug "IP address: " + add$
		
		mask = *ipinfo\dwMask
		msk$ = PeekS (inet_ntoa_ (mask))
		Debug "Subnet mask: " + msk$

		type = *ipinfo\wType
		
		If type & #MIB_IPADDR_PRIMARY
			Debug "Primary IP address for interface"
		EndIf

		If type & #MIB_IPADDR_DYNAMIC
			Debug "Dynamically-allocated IP address"
		EndIf

		If type & #MIB_IPADDR_DISCONNECTED
			Debug "Address is on disconnected interface"
		EndIf

		If type & #MIB_IPADDR_DELETED
			Debug "Address is being deleted"
		EndIf

		If type & #MIB_IPADDR_TRANSIENT
			Debug "Transient address"
		EndIf

		If mask = IntFromAddress (subnet$)
			Debug "*** Part of subnet " + subnet$
		Else
			Debug "NOT part of subnet " + subnet$
		EndIf
		
		network$ = PeekS (inet_ntoa_ (ip & mask))
		Debug "BONUS: Network address: " + network$

		Debug ""

	EndIf

	*ipinfo = *ipinfo + SizeOf (MIB_IPADDRROW)
		
Next
Last edited by Hi-Toro on Sat Oct 10, 2009 4:34 pm, edited 1 time in total.
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: List resources on local area network

Post by SFSxOI »

Hi-Toro wrote:Hello all,

I thought I'd post this since it might be useful to others -- it looks up and lists all resources on a Windows LAN (dunno what'll happen if you have a Linux or other PC attached!), showing sizes of shared disks and computer names/IP addresses (the IP lookup is Flype's code).

I've no idea how well it'll work with a router/switch, but it works on my setup, which is a server that has two PCs going directly into it.

I've made it as fault-proof as possible, but it just shows how to retrieve this information and prints it to the Debug Output window.

I think it should work with Windows 2000 or above. Don't be surprised if it appears to pause for long periods, as Windows can take its time in finding network resources! I've never understood why this is...

(The only minor thing bugging me at the moment is that it prints the public IP for the client running the program, rather than the LAN IP, though it lists the other PCs on the LAN with their local IPs.)

Code: Select all


; TURN ON DEBUGGER TO SEE THE OUTPUT!

Procedure.s GetIP (ComputerName.s)
	; By Flype! (Just reformatted to my preference.)
	If ComputerName
		If WSAStartup_ ((1<<8|1), wsa.WSADATA) = #NOERROR
			*host.HOSTENT = gethostbyname_ (ComputerName)
			WSACleanup_ ()
			If *host
				ProcedureReturn PeekS (inet_ntoa_ (PeekL (PeekL (*host\h_addr_list))))
			EndIf
		EndIf
	EndIf
EndProcedure

; -----------------------------------------------------------------------------
; Enumerate LAN resources...
; -----------------------------------------------------------------------------

Procedure ShowNetworkInfo (*resource.NETRESOURCE = #Null, indent = 0)

	; Indent string for debugging recursive function...

	in$ = LSet ("", 8 * indent, "-")
	If indent > 0
		in$ = in$ + "> "
	EndIf

	chunk = 262144 ; 4 times the M$-suggested amount (in 1992-1996)...
	
	openresult = WNetOpenEnum_ (#RESOURCE_GLOBALNET, #RESOURCETYPE_ANY, 0, *resource, @enum)
	
	Select openresult
	
		Case #NO_ERROR

			size = chunk
			
			; Try to enumerate resources. In the unlikely event that the buffer is too small,
			; add another 'chunk' of memory until OK...
			
			; Probably won't be relevant except for massive business networks anyway...
			
			Repeat
	
				count = $FFFFFFFF
	
				*mem = ReAllocateMemory (*mem, size)
	
				enumresult = WNetEnumResource_ (enum, @count, *mem, @size)
				
				If enumresult = #ERROR_MORE_DATA
					size = size + chunk
				EndIf
				
			Until enumresult <> #ERROR_MORE_DATA
			
			Select enumresult
			
				Case #NO_ERROR
	
					; ---------------------------------------------------------
					; All OK, enumerate this resource...
					; ---------------------------------------------------------

					For loop = 0 To count - 1
					
						*temp.NETRESOURCE = *mem + (loop * SizeOf (NETRESOURCE))
			
						iterate = #False ; Used at end of loop to enumerate this resource...
						
						; -------------------------------------------------------------
						; Read available strings for resource...
						; -------------------------------------------------------------
		
						If *temp\lpLocalName <> #Null
							Debug in$ + "Local resource name: " + PeekS (*temp\lpLocalName)
						EndIf
						
						If *temp\lpRemoteName <> #Null
						
							name$ = PeekS (*temp\lpRemoteName)
							
							If Left (name$, 2) = "\\"
								name$ = Mid (name$, 3)
							EndIf
							
							info$ = in$ + "Remote resource name: " + name$

							If *temp\dwDisplayType = #RESOURCEDISPLAYTYPE_SERVER
								ip$ = GetIP (name$)
								If ip$ <> ""
									info$ = info$ + " (" + ip$ + ")"
								EndIf
							EndIf

							Debug info$
							
						EndIf
						
						If *temp\lpProvider <> #Null
							Debug in$ + "Network resource provider: " + PeekS (*temp\lpProvider)
						EndIf
			
						If *temp\lpComment <> #Null
							comment$ = PeekS (*temp\lpComment)
							If comment$ = ""
								comment$ = "[No comment set]"
							EndIf
							Debug in$ + "Comment: " + comment$
						EndIf
						
						; -------------------------------------------------------------
						; Get scope of resource...
						; -------------------------------------------------------------
		
						Select *temp\dwScope
			
							Case #RESOURCE_CONNECTED
							
								Debug in$ + "Scope: Currently connected resource"
			
							Case #RESOURCE_GLOBALNET
			
								Debug in$ + "Scope: Network resource"
			
								; NOTE: dwUsage is only valid for #RESOURCE_GLOBALNET...
								
								If *temp\dwUsage And #RESOURCEUSAGE_CONNECTABLE
									Debug in$ + "Usage: Connectable resource"
								EndIf
			
								If *temp\dwUsage And #RESOURCEUSAGE_CONTAINER
								
									Debug in$ + "Usage: Container resource"
									
									If *temp\dwType <> #RESOURCETYPE_DISK
										iterate = #True ; Can iterate through this resource...
									EndIf
									
								EndIf

							Case #RESOURCE_REMEMBERED
							
								Debug in$ + "Scope: Persistent resource"
			
						EndSelect
			
						; -------------------------------------------------------------
						; Get type of resource...
						; -------------------------------------------------------------
		
						Select *temp\dwType
						
							Case #RESOURCETYPE_ANY
								Debug in$ + "Share type: Undefined (probably a container)"
							
							Case #RESOURCETYPE_DISK
							
								Debug in$ + "Share type: Disk"
		
								; Get disk size/space...
								
								If *temp\lpRemoteName <> #Null
								
									SetErrorMode_ (#SEM_FAILCRITICALERRORS)
					
									If GetDiskFreeSpaceEx_ (*temp\lpRemoteName, @ignored.q, @totalbytes.q, @freebytes.q)
									
										total = totalbytes / 1024 / 1024 / 1024
										free = freebytes / 1024 / 1024 / 1024
									
										Debug in$ + "Share size: " + StrU (total, #PB_Quad) + " GB"
										Debug in$ + "Free space: " + StrU (free, #PB_Quad) + " GB"
									
									Else
									
										Debug "Couldn't read disk size/space"
								
									EndIf
		
								SetErrorMode_ (0)
		
								EndIf
														
							Case #RESOURCETYPE_PRINT
								Debug in$ + "Share type: Printer"
							
						EndSelect
							
						; -------------------------------------------------------------
						; How the resource is displayed in a network browser GUI...
						; -------------------------------------------------------------
		
						Select *temp\dwDisplayType
							Case #RESOURCEDISPLAYTYPE_DOMAIN
								Debug in$ + "Displayed as: Domain"
							Case #RESOURCEDISPLAYTYPE_GENERIC
								Debug in$ + "Displayed as: Generic"
							Case #RESOURCEDISPLAYTYPE_SERVER
								Debug in$ + "Displayed as: Server"
							Case #RESOURCEDISPLAYTYPE_SHARE
								Debug in$ + "Displayed as: Share"
							Default
								Debug in$ + "Displayed as: Unknown (probably root node)"
						EndSelect
						
						Debug ""
		
						; -------------------------------------------------------------
						; Try to enumerate this resource (recursive function call)...
						; -------------------------------------------------------------
		
						If iterate
							indent = indent + 1
							ShowNetworkInfo (*temp, indent)
							indent = indent - 1
						EndIf
						
					Next
				
				Case #ERROR_NO_MORE_ITEMS
				
					; ---------------------------------------------------------
					; Can't enumerate within this resource...
					; ---------------------------------------------------------

					Debug in$ + "No items to enumerate in this resource"
					Debug ""
					
			EndSelect
		
			FreeMemory (*mem)
			WNetCloseEnum_ (enum)

		Case #ERROR_NOT_CONTAINER

			Debug in$ + "The specified resource is not a container"
			Debug ""

		Case #ERROR_INVALID_PARAMETER

			Debug in$ + "WNetOpenEnum received an invalid dwScope or dwType parameter"
			Debug ""

		Case #ERROR_NO_NETWORK

			Debug in$ + "No network connected to resource being enumerated"
			Debug ""

		Case #ERROR_EXTENDED_ERROR

			Debug in$ + "Extended error information available:"

			; Untested -- haven't run into this and don't know how to test! Should work, though...
			
			*errorbuffer = AllocateMemory (1024)
			*providerbuffer = AllocateMemory (1024)
			
			If WNetGetLastError_ (@neterror, *errorbuffer, 1024, *providerbuffer, 1024) = #NO_ERROR
				Debug PeekS (*providerbuffer) + " reports: " + PeekS (*errorbuffer)
			EndIf

			Debug ""

		Default
		
			Debug in$ + "Unexpected error on opening resource. (Eg. May not support enumeration.)"
			
			; This is (ironically) expected sometimes! Eg. "NetDrive Network" doesn't
			; support enumeration and reports "The request is not supported" when
			; GetLastError () is called...

			Debug ""

		EndSelect
		
EndProcedure

Debug ""
Debug "Scanning LAN -- this may take some time!"
Debug ""

ShowNetworkInfo ()


OK, I got a little lost or something here. Is this supposed to also show the IP address and subnet public IP? Doesn't show up here on windows 7. Other then that seems to work fine, good work, thank you. :)
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

Hi SFS,

It should show at least one IP address for each PC, but I've since realised that each PC may have more than one IP, and the GetIP function in that code only shows the first IP for the PC. I posted code above that lists all IPs for the local PC...

[EDIT: I wrote it on Windows 7 and XP BTW!]

[EDIT 2: I finally realised you're probably talking about Rook's GUI version -- it seems he added those fields to the GUI but just didn't add the functionality to fill them in. The original code I posted should at least show the IP address for each computer in the Debug output.]
Last edited by Hi-Toro on Sun Oct 11, 2009 10:58 pm, edited 4 times in total.
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

[EDIT Doh! Already posted this code, sorry.]
Last edited by Hi-Toro on Sat Oct 10, 2009 4:55 pm, edited 1 time in total.
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

I've also been listing all network adapters on the system (this is similar to what IPConfig shows) -- this is for Windows XP and above only:

Code: Select all


; IMPORTANT: Only for Windows XP and above! TURN DEBUGGER ON TO SEE OUTPUT!

; Only taking IPv4 protocol into account here...

; Use command line -> ipconfig to see subnet mask for each network adapter on your system...

Procedure.l IntFromAddress (ip$)
	ProcedureReturn inet_addr_ (@ip$)
EndProcedure

Procedure.s AddressFromInt (ip.l)
	ProcedureReturn PeekS (inet_ntoa_ (ip))
EndProcedure

#MAX_ADAPTER_ADDRESS_LENGTH = 8
#ERROR_ADDRESS_NOT_ASSOCIATED = 1228

#IF_TYPE_OTHER = 1 ; "Some other type of network interface"
#IF_TYPE_ETHERNET_CSMACD = 6 ; "An Ethernet network interface"
#IF_TYPE_ISO88025_TOKENRING = 9 ; "A token ring network interface"
#IF_TYPE_PPP = 23 ; "A PPP network interface"
#IF_TYPE_SOFTWARE_LOOPBACK = 24 ; "A software loopback network interface"
#IF_TYPE_ATM = 37 ; "An ATM network interface"
#IF_TYPE_IEEE80211 = 71 ; "An IEEE 802.11 wireless network interface. On Windows Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211. On earlier versions of Windows, wireless network cards are reported as IF_TYPE_ETHERNET_CSMACD"
#IF_TYPE_TUNNEL = 131 ; "A tunnel type encapsulation network interface"
#IF_TYPE_IEEE1394 = 144 ; "An IEEE 1394 (Firewire) high performance serial bus network interface"

#IP_ADAPTER_DDNS_ENABLED = $1 ; "Dynamic DNS is enabled on this adapter"
#IP_ADAPTER_REGISTER_ADAPTER_SUFFIX = $2 ; "Register the DNS suffix for this adapter"
#IP_ADAPTER_DHCP_ENABLED = $4 ; "The Dynamic Host Configuration Protocol (DHCP) is enabled on this adapter"
#IP_ADAPTER_RECEIVE_ONLY = $8 ; "The adapter is a receive-only adapter"
#IP_ADAPTER_NO_MULTICAST = $10 ; "The adapter is not a multicast recipient" ; 
#IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG = $20 ; "The adapter contains other IPv6-specific stateful configuration information"

#IfOperStatusUp = 1 ; "The interface is up and able to pass packets"
#IfOperStatusDown = 2; "The interface is down and not in a condition to pass packets. The IfOperStatusDown state has two meanings, depending on the value of AdminStatus member. If AdminStatus is not set to NET_IF_ADMIN_STATUS_DOWN and ifOperStatus is set to IfOperStatusDown then a fault condition is presumed to exist on the interface. If AdminStatus is set to IfOperStatusDown, then ifOperStatus will normally also be set to IfOperStatusDown or IfOperStatusNotPresent and there is not necessarily a fault condition on the interface."
#IfOperStatusTesting = 3 ; "The interface is in testing mode"
#IfOperStatusUnknown = 4 ; "The operational status of the interface is unknown"
#IfOperStatusDormant = 5 ; "The interface is not actually in a condition to pass packets (it is not up), but is in a pending state, waiting for some external event. For on-demand interfaces, this new state identifies the situation where the interface is waiting for events to place it in the IfOperStatusUp state."
#IfOperStatusNotPresent = 6 ; "A refinement on the IfOperStatusDown state which indicates that the relevant interface is down specifically because some component (typically, a hardware component) is not present in the managed system."
#IfOperStatusLowerLayerDown = 7 ; "A refinement on the IfOperStatusDown state. This new state indicates that this interface runs on top of one or more other interfaces and that this interface is down specifically because one or more of these lower-layer interfaces are down."

Structure IP_ADAPTER_ADDRESSES
	  
	;  union {ULONGLONG Alignment; struct {ULONG Length; DWORD IfIndex; } ; } ;
	
	Length.l ; unsigned
	IfIndex.l
	*Next.IP_ADAPTER_ADDRESSES
	*AdapterName
	*FirstUnicastAddress;.PIP_ADAPTER_UNICAST_ADDRESS
	*FirstAnycastAddress;.PIP_ADAPTER_ANYCAST_ADDRESS
	*FirstMulticastAddress;.PIP_ADAPTER_MULTICAST_ADDRESS
	*FirstDnsServerAddress;.PIP_ADAPTER_DNS_SERVER_ADDRESS
	*DnsSuffix;.PWCHAR
	*Description;.PWCHAR
	*FriendlyName;.PWCHAR
	PhysicalAddress.b [#MAX_ADAPTER_ADDRESS_LENGTH]
	PhysicalAddressLength.l
	Flags.l
	Mtu.l
	IfType.l
	OperStatus.l
	Ipv6IfIndex.l
	ZoneIndices.l [16]
	*FirstPrefix;.PIP_ADAPTER_PREFIX

; Vista-only from here! Ignoring for now...

;	TransmitLinkSpeed.q ; unsigned
;	ReceiveLinkSpeed.q ; unsigned
;	*FirstWinsServerAddress;.PIP_ADAPTER_WINS_SERVER_ADDRESS_LH
;	*FirstGatewayAddress;.PIP_ADAPTER_GATEWAY_ADDRESS_LH
;	Ipv4Metric.l ; unsigned
;	Ipv6Metric.l ; unsigned
;	Luid.IF_LUID
;	Dhcpv4Server.SOCKET_ADDRESS
;	CompartmentId.NET_IF_COMPARTMENT_ID
;	NetworkGuid.NET_IF_NETWORK_GUID
;	ConnectionType.NET_IF_CONNECTION_TYPE
;	TunnelType.TUNNEL_TYPE
;	Dhcpv6Server.SOCKET_ADDRESS
;	Dhcpv6ClientDuid.b [#MAX_DHCPV6_DUID_LENGTH]
;	Dhcpv6ClientDuidLength.l ; unsigned
;	Dhcpv6Iaid.l ; unsigned

; Server 2008-only from here!

;	*FirstDnsSuffix.PIP_ADAPTER_DNS_SUFFIX

EndStructure

Structure SOCKET_ADDRESS
	*lpSockaddr
	iSockaddrLength.l
EndStructure

Structure IP_ADAPTER_PREFIX

	; union { ULONGLONG Alignment; struct { ULONG Length; DWORD Flags; } ; } ;
	
	Length.l
	Flags.l
	
	*Next.IP_ADAPTER_PREFIX
	Address.SOCKET_ADDRESS
	PrefixLength.l

EndStructure  
  
  
dll = OpenLibrary (#PB_Any, "iphlpapi.dll")

If dll

	GetAdaptersAddresses = GetFunction (dll, "GetAdaptersAddresses")
	
	If GetAdaptersAddresses
	
		tablesize = SizeOf (IP_ADAPTER_ADDRESSES)
		*table.IP_ADAPTER_ADDRESSES = AllocateMemory (tablesize)
		
		valid = #False
		
		Repeat
		
			Select CallFunctionFast (GetAdaptersAddresses, #AF_INET, 0, #Null, *table, @tablesize)
				
				Case #NO_ERROR

					; Can exit loop now...
					
					valid = #True
		
				Case #ERROR_ADDRESS_NOT_ASSOCIATED
				
					Debug "Epic fail! Not associated, whatever that means..."
					End
					
				Case #ERROR_BUFFER_OVERFLOW
				
					; Increase buffer size and try again...
					
					*table = ReAllocateMemory (*table, tablesize)
		
				Case #ERROR_INVALID_PARAMETER

					Debug "Epic fail! Invalid parameter passed to GetAdaptersAddresses function!"
					End
							
				Case #ERROR_NOT_ENOUGH_MEMORY

					Debug "Epic fail! Not enough memory!"
					End
		
				Case #ERROR_NO_DATA

					Debug "Epic fail! No data, whatever that means..."
					End
					
				Default

					Debug "Epic fail! Try calling GetError for further information..."
					End
		
			EndSelect
		
		Until valid

	Else
		Debug "Couldn't get GetAdaptersAddresses handle"
	EndIf
	
Else
	Debug "Failed to open iphlpapi.dll"
EndIf

Debug ""

*info.IP_ADAPTER_ADDRESSES = *table

While *info

	Debug "Interface #" + Str (*info\IfIndex)
	Debug "Adapter name/GUID: " + PeekS (*info\AdapterName, -1, #PB_Ascii)
	
	Debug "Description: " + PeekS (*info\Description, -1, #PB_Unicode)
	Debug "Friendly name: " + PeekS (*info\FriendlyName, -1, #PB_Unicode)
	Debug "MTU size: " + Str (*info\Mtu) + " bytes"
	
	Select *info\ifType
		Case #IF_TYPE_OTHER
			iftype$ = "Some other type of network interface"
		Case #IF_TYPE_ETHERNET_CSMACD
			iftype$ = "An Ethernet network interface"
		Case #IF_TYPE_ISO88025_TOKENRING
			iftype$ = "A token ring network interface"
		Case #IF_TYPE_PPP
			iftype$ = "A PPP network interface"
		Case #IF_TYPE_SOFTWARE_LOOPBACK
			iftype$ = "A software loopback network interface"
		Case #IF_TYPE_ATM
			iftype$ = "An ATM network interface"
		Case #IF_TYPE_IEEE80211
			iftype$ = "An IEEE 802.11 wireless network interface. On Windows Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211. On earlier versions of Windows, wireless network cards are reported as IF_TYPE_ETHERNET_CSMACD"
		Case #IF_TYPE_TUNNEL
			iftype$ = "A tunnel type encapsulation network interface"
		Case #IF_TYPE_IEEE1394
			iftype$ = "An IEEE 1394 (Firewire) high performance serial bus network interface"
	EndSelect

	Debug "Interface type: " + iftype$
	
	; Get MAC address:
		
	If *info\PhysicalAddressLength
		mac$ = ""
		For byte = 0 To *info\PhysicalAddressLength - 1
			mac$ = mac$ + RSet (Hex (*info\PhysicalAddress [byte] & 255), 2, "0") + "-"
		Next
		mac$ = Left (mac$, Len (mac$) - 1) ; Strip last "-"
		Debug "MAC or physical address: " + mac$
	EndIf

	If *info\Flags & #IP_ADAPTER_DDNS_ENABLED
		Debug "Dynamic DNS is enabled on this adapter"
	EndIf

	If *info\Flags & #IP_ADAPTER_REGISTER_ADAPTER_SUFFIX
		Debug "Register the DNS suffix for this adapter"
	EndIf

	If *info\Flags & #IP_ADAPTER_DHCP_ENABLED
		Debug "The Dynamic Host Configuration Protocol (DHCP) is enabled on this adapter"
	EndIf

	If *info\Flags & #IP_ADAPTER_RECEIVE_ONLY
		Debug "The adapter is a receive-only adapter"
	EndIf

	If *info\Flags & #IP_ADAPTER_NO_MULTICAST
		Debug "The adapter is not a multicast recipient"
	EndIf

	If *info\Flags & #IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG
		Debug "The adapter contains other IPv6-specific stateful configuration information"
	EndIf

	Select *info\OperStatus
		Case #IfOperStatusUp = 1
			status$ = "The interface is up and able to pass packets"
		Case #IfOperStatusDown = 2
			status$ = "The interface is down and not in a condition to pass packets"
		Case #IfOperStatusTesting = 3
			status$ = "The interface is in testing mode"
		Case #IfOperStatusUnknown = 4
			status$ = "The operational status of the interface is unknown"
		Case #IfOperStatusDormant = 5
			status$ = "The interface is not actually in a condition to pass packets (it is not up), but is in a pending state, waiting for some external event"
		Case #IfOperStatusNotPresent = 6
			status$ = "The relevant interface is down specifically because some component is not present in the managed system."
		Case #IfOperStatusLowerLayerDown = 7
			status$ = "This interface runs on top of one or more other interfaces and this interface is down specifically because one or more of these lower-layer interfaces are down"
	EndSelect

	Debug "Status: " + status$
	
	Debug ""

	*info = *info\Next

Wend

End
Last edited by Hi-Toro on Sat Oct 10, 2009 4:50 pm, edited 1 time in total.
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

Lastly (for now), this is some of the above code combined to list the IP address/subnet mask assigned to each adapter. I should put the IPs into a list, rather than calling ShowIPTable for each adapter, but it's just a quick hack to test the theory!

(For Windows XP and above only.)

Code: Select all


; TURN DEBUGGER ON TO SEE OUTPUT!

; Use command line -> ipconfig to see subnet mask for each network adapter on your system...

Procedure.l IntFromAddress (ip$)
	ProcedureReturn inet_addr_ (@ip$)
EndProcedure

Procedure.s AddressFromInt (ip.l)
	ProcedureReturn PeekS (inet_ntoa_ (ip))
EndProcedure

Structure MIB_IPADDRROW
	dwAddr.l
	dwIndex.l
	dwMask.l
	dwBCastAddr.l
	dwReasmSize.l
	unused1.w
	wType.w
EndStructure

Structure MIB_IPADDRTABLE
	dwNumEntries.l
	*ips.MIB_IPADDRROW
EndStructure

#MIB_IPADDR_PRIMARY = $0001
#MIB_IPADDR_DYNAMIC = $0004
#MIB_IPADDR_DISCONNECTED = $0008
#MIB_IPADDR_DELETED = $0040
#MIB_IPADDR_TRANSIENT = $0080

Procedure ShowIPTable (adapter = 0, subnet$ = "")

	tablesize = SizeOf (MIB_IPADDRTABLE)
	*table.MIB_IPADDRTABLE = AllocateMemory (tablesize)
	
	valid = #False
	
	Repeat
	
		Select GetIpAddrTable_ (*table, @tablesize, #True)
			
			Case #NO_ERROR
				valid = #True
	
			Case #ERROR_INSUFFICIENT_BUFFER
			
				*table = ReAllocateMemory (*table, tablesize)
	
			Case #ERROR_INVALID_PARAMETER
				Debug "Param"
	
			Case #ERROR_NOT_SUPPORTED
				Debug "Not supported"
	
			Default
				Debug "Call GetError!"
			
		EndSelect
	
	Until valid
	
	*ipinfo.MIB_IPADDRROW = @*table\ips
	
	For loop = 0 To *table\dwNumEntries - 1
	
		interfaceindex = *ipinfo\dwIndex
	
		If interfaceindex > 0
		
			If interfaceindex = adapter
	
;				Debug "Interface #" + Str (interfaceindex)
				
				ip = *ipinfo\dwAddr
				add$ = PeekS (inet_ntoa_ (ip))
				Debug "IP address: " + add$
				
				mask = *ipinfo\dwMask
				msk$ = PeekS (inet_ntoa_ (mask))
				Debug "Subnet mask: " + msk$
		
;				type = *ipinfo\wType
				
;				If type & #MIB_IPADDR_PRIMARY
;					Debug "Primary IP address for interface"
;				EndIf
		
;				If type & #MIB_IPADDR_DYNAMIC
;					Debug "Dynamically-allocated IP address"
;				EndIf
		
;				If type & #MIB_IPADDR_DISCONNECTED
;					Debug "Address is on disconnected interface"
;				EndIf
		
;				If type & #MIB_IPADDR_DELETED
;					Debug "Address is being deleted"
;				EndIf
		
;				If type & #MIB_IPADDR_TRANSIENT
;					Debug "Transient address"
;				EndIf
		
;				If mask = IntFromAddress (subnet$)
;					Debug "*** Part of subnet " + subnet$
;				Else
;					Debug "NOT part of subnet " + subnet$
;				EndIf
				
;				network$ = PeekS (inet_ntoa_ (ip & mask))
;				Debug "Network address: " + network$

			EndIf
				
		EndIf
	
		*ipinfo = *ipinfo + SizeOf (MIB_IPADDRROW)
			
	Next
	
EndProcedure

; IMPORTANT: Only for Windows XP and above! TURN DEBUGGER ON TO SEE OUTPUT!

; Only taking IPv4 protocol into account here...

; Use command line -> ipconfig to see subnet mask for each network adapter on your system...

#MAX_ADAPTER_ADDRESS_LENGTH = 8
#ERROR_ADDRESS_NOT_ASSOCIATED = 1228

#IF_TYPE_OTHER = 1 ; "Some other type of network interface"
#IF_TYPE_ETHERNET_CSMACD = 6 ; "An Ethernet network interface"
#IF_TYPE_ISO88025_TOKENRING = 9 ; "A token ring network interface"
#IF_TYPE_PPP = 23 ; "A PPP network interface"
#IF_TYPE_SOFTWARE_LOOPBACK = 24 ; "A software loopback network interface"
#IF_TYPE_ATM = 37 ; "An ATM network interface"
#IF_TYPE_IEEE80211 = 71 ; "An IEEE 802.11 wireless network interface. On Windows Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211. On earlier versions of Windows, wireless network cards are reported as IF_TYPE_ETHERNET_CSMACD"
#IF_TYPE_TUNNEL = 131 ; "A tunnel type encapsulation network interface"
#IF_TYPE_IEEE1394 = 144 ; "An IEEE 1394 (Firewire) high performance serial bus network interface"

#IP_ADAPTER_DDNS_ENABLED = $1 ; "Dynamic DNS is enabled on this adapter"
#IP_ADAPTER_REGISTER_ADAPTER_SUFFIX = $2 ; "Register the DNS suffix for this adapter"
#IP_ADAPTER_DHCP_ENABLED = $4 ; "The Dynamic Host Configuration Protocol (DHCP) is enabled on this adapter"
#IP_ADAPTER_RECEIVE_ONLY = $8 ; "The adapter is a receive-only adapter"
#IP_ADAPTER_NO_MULTICAST = $10 ; "The adapter is not a multicast recipient" ; 
#IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG = $20 ; "The adapter contains other IPv6-specific stateful configuration information"

#IfOperStatusUp = 1 ; "The interface is up and able to pass packets"
#IfOperStatusDown = 2; "The interface is down and not in a condition to pass packets. The IfOperStatusDown state has two meanings, depending on the value of AdminStatus member. If AdminStatus is not set to NET_IF_ADMIN_STATUS_DOWN and ifOperStatus is set to IfOperStatusDown then a fault condition is presumed to exist on the interface. If AdminStatus is set to IfOperStatusDown, then ifOperStatus will normally also be set to IfOperStatusDown or IfOperStatusNotPresent and there is not necessarily a fault condition on the interface."
#IfOperStatusTesting = 3 ; "The interface is in testing mode"
#IfOperStatusUnknown = 4 ; "The operational status of the interface is unknown"
#IfOperStatusDormant = 5 ; "The interface is not actually in a condition to pass packets (it is not up), but is in a pending state, waiting for some external event. For on-demand interfaces, this new state identifies the situation where the interface is waiting for events to place it in the IfOperStatusUp state."
#IfOperStatusNotPresent = 6 ; "A refinement on the IfOperStatusDown state which indicates that the relevant interface is down specifically because some component (typically, a hardware component) is not present in the managed system."
#IfOperStatusLowerLayerDown = 7 ; "A refinement on the IfOperStatusDown state. This new state indicates that this interface runs on top of one or more other interfaces and that this interface is down specifically because one or more of these lower-layer interfaces are down."

Structure IP_ADAPTER_ADDRESSES
	  
	;  union {ULONGLONG Alignment; struct {ULONG Length; DWORD IfIndex; } ; } ;
	
	Length.l ; unsigned
	IfIndex.l
	*Next.IP_ADAPTER_ADDRESSES
	*AdapterName
	*FirstUnicastAddress;.PIP_ADAPTER_UNICAST_ADDRESS
	*FirstAnycastAddress;.PIP_ADAPTER_ANYCAST_ADDRESS
	*FirstMulticastAddress;.PIP_ADAPTER_MULTICAST_ADDRESS
	*FirstDnsServerAddress;.PIP_ADAPTER_DNS_SERVER_ADDRESS
	*DnsSuffix;.PWCHAR
	*Description;.PWCHAR
	*FriendlyName;.PWCHAR
	PhysicalAddress.b [#MAX_ADAPTER_ADDRESS_LENGTH]
	PhysicalAddressLength.l
	Flags.l
	Mtu.l
	IfType.l
	OperStatus.l
	Ipv6IfIndex.l
	ZoneIndices.l [16]
	*FirstPrefix;.PIP_ADAPTER_PREFIX

; Vista-only from here! Ignoring for now...

;	TransmitLinkSpeed.q ; unsigned
;	ReceiveLinkSpeed.q ; unsigned
;	*FirstWinsServerAddress;.PIP_ADAPTER_WINS_SERVER_ADDRESS_LH
;	*FirstGatewayAddress;.PIP_ADAPTER_GATEWAY_ADDRESS_LH
;	Ipv4Metric.l ; unsigned
;	Ipv6Metric.l ; unsigned
;	Luid.IF_LUID
;	Dhcpv4Server.SOCKET_ADDRESS
;	CompartmentId.NET_IF_COMPARTMENT_ID
;	NetworkGuid.NET_IF_NETWORK_GUID
;	ConnectionType.NET_IF_CONNECTION_TYPE
;	TunnelType.TUNNEL_TYPE
;	Dhcpv6Server.SOCKET_ADDRESS
;	Dhcpv6ClientDuid.b [#MAX_DHCPV6_DUID_LENGTH]
;	Dhcpv6ClientDuidLength.l ; unsigned
;	Dhcpv6Iaid.l ; unsigned

; Server 2008-only from here!

;	*FirstDnsSuffix.PIP_ADAPTER_DNS_SUFFIX

EndStructure

Structure SOCKET_ADDRESS
	*lpSockaddr
	iSockaddrLength.l
EndStructure

Structure IP_ADAPTER_PREFIX
	; union { ULONGLONG Alignment; struct { ULONG Length; DWORD Flags; } ; } ;
	Length.l
	Flags.l
	*Next.IP_ADAPTER_PREFIX
	Address.SOCKET_ADDRESS
	PrefixLength.l
EndStructure
  
dll = OpenLibrary (#PB_Any, "iphlpapi.dll")

If dll

	GetAdaptersAddresses = GetFunction (dll, "GetAdaptersAddresses")
	
	If GetAdaptersAddresses
	
		tablesize = SizeOf (IP_ADAPTER_ADDRESSES)
		*table.IP_ADAPTER_ADDRESSES = AllocateMemory (tablesize)
		
		valid = #False
		
		Repeat
		
			Select CallFunctionFast (GetAdaptersAddresses, #AF_INET, 0, #Null, *table, @tablesize)
				
				Case #NO_ERROR

					; Can exit loop now...
					
					valid = #True
		
				Case #ERROR_ADDRESS_NOT_ASSOCIATED
				
					Debug "Epic fail! Not associated, whatever that means..."
					End
					
				Case #ERROR_BUFFER_OVERFLOW
				
					; Increase buffer size and try again...
					
					*table = ReAllocateMemory (*table, tablesize)
		
				Case #ERROR_INVALID_PARAMETER

					Debug "Epic fail! Invalid parameter passed to GetAdaptersAddresses function!"
					End
							
				Case #ERROR_NOT_ENOUGH_MEMORY

					Debug "Epic fail! Not enough memory!"
					End
		
				Case #ERROR_NO_DATA

					Debug "Epic fail! No data, whatever that means..."
					End
					
				Default

					Debug "Epic fail! Try calling GetError for further information..."
					End
		
			EndSelect
		
		Until valid

	Else
		Debug "Couldn't get GetAdaptersAddresses handle"
	EndIf
	
Else
	Debug "Failed to open iphlpapi.dll"
EndIf

Debug ""

*info.IP_ADAPTER_ADDRESSES = *table

While *info

	Debug "-----------------------------------------------------------------------"
	Debug "New adapter entry..."
	Debug "-----------------------------------------------------------------------"
	Debug ""
;	Debug "Interface #" + Str (*info\IfIndex)
	Debug "Adapter name/GUID: " + PeekS (*info\AdapterName, -1, #PB_Ascii)

	Debug ""
	ShowIPTable (*info\IfIndex)
	Debug ""
		
	Debug "Description: " + PeekS (*info\Description, -1, #PB_Unicode)
	Debug "Friendly name: " + PeekS (*info\FriendlyName, -1, #PB_Unicode)
	Debug "MTU size: " + Str (*info\Mtu) + " bytes"
	
	Select *info\ifType
		Case #IF_TYPE_OTHER
			iftype$ = "Some other type of network interface"
		Case #IF_TYPE_ETHERNET_CSMACD
			iftype$ = "An Ethernet network interface"
		Case #IF_TYPE_ISO88025_TOKENRING
			iftype$ = "A token ring network interface"
		Case #IF_TYPE_PPP
			iftype$ = "A PPP network interface"
		Case #IF_TYPE_SOFTWARE_LOOPBACK
			iftype$ = "A software loopback network interface"
		Case #IF_TYPE_ATM
			iftype$ = "An ATM network interface"
		Case #IF_TYPE_IEEE80211
			iftype$ = "An IEEE 802.11 wireless network interface. On Windows Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211. On earlier versions of Windows, wireless network cards are reported as IF_TYPE_ETHERNET_CSMACD"
		Case #IF_TYPE_TUNNEL
			iftype$ = "A tunnel type encapsulation network interface"
		Case #IF_TYPE_IEEE1394
			iftype$ = "An IEEE 1394 (Firewire) high performance serial bus network interface"
	EndSelect

	Debug "Interface type: " + iftype$
	
	; Get MAC address:
		
	If *info\PhysicalAddressLength
		mac$ = ""
		For byte = 0 To *info\PhysicalAddressLength - 1
			mac$ = mac$ + RSet (Hex (*info\PhysicalAddress [byte] & 255), 2, "0") + "-"
		Next
		mac$ = Left (mac$, Len (mac$) - 1) ; Strip last "-"
		Debug "MAC or physical address: " + mac$
	EndIf

	If *info\Flags & #IP_ADAPTER_DDNS_ENABLED
		Debug "Dynamic DNS is enabled on this adapter"
	EndIf

	If *info\Flags & #IP_ADAPTER_REGISTER_ADAPTER_SUFFIX
		Debug "Register the DNS suffix for this adapter"
	EndIf

	If *info\Flags & #IP_ADAPTER_DHCP_ENABLED
		Debug "The Dynamic Host Configuration Protocol (DHCP) is enabled on this adapter"
	EndIf

	If *info\Flags & #IP_ADAPTER_RECEIVE_ONLY
		Debug "The adapter is a receive-only adapter"
	EndIf

	If *info\Flags & #IP_ADAPTER_NO_MULTICAST
		Debug "The adapter is not a multicast recipient"
	EndIf

	If *info\Flags & #IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG
		Debug "The adapter contains other IPv6-specific stateful configuration information"
	EndIf

	Select *info\OperStatus
		Case #IfOperStatusUp = 1
			status$ = "The interface is up and able to pass packets"
		Case #IfOperStatusDown = 2
			status$ = "The interface is down and not in a condition to pass packets"
		Case #IfOperStatusTesting = 3
			status$ = "The interface is in testing mode"
		Case #IfOperStatusUnknown = 4
			status$ = "The operational status of the interface is unknown"
		Case #IfOperStatusDormant = 5
			status$ = "The interface is not actually in a condition to pass packets (it is not up), but is in a pending state, waiting for some external event"
		Case #IfOperStatusNotPresent = 6
			status$ = "The relevant interface is down specifically because some component is not present in the managed system."
		Case #IfOperStatusLowerLayerDown = 7
			status$ = "This interface runs on top of one or more other interfaces and this interface is down specifically because one or more of these lower-layer interfaces are down"
	EndSelect

	Debug "Status: " + status$
	
	Debug ""

	*info = *info\Next

Wend

End
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 270
Joined: Sat Apr 26, 2003 3:23 pm

Re: List resources on local area network

Post by Hi-Toro »

More from my continuing journey into Windows networking information -- I realise this is of limited interest in general, but it should at least be useful when somebody wants to do any of this stuff in the future.

Anyway, this gets your computer's list of DNS servers:

Code: Select all


#MAX_HOSTNAME_LEN = 128
#MAX_DOMAIN_NAME_LEN = 128
#MAX_SCOPE_ID_LEN = 256

#BROADCAST_NODETYPE = $1 ; "A broadcast nodetype"
#PEER_TO_PEER_NODETYPE = $2 ; "A peer To peer nodetype"
#MIXED_NODETYPE = $4 ; "A mixed nodetype"
#HYBRID_NODETYPE = $8 ; "A hybrid nodetype"

Structure IP_ADDR_STRING
	*Next.IP_ADDR_STRING
	IpAddress.b [16]
	IpMask.b [16]
	Context.l
EndStructure

Structure FIXED_INFO
	HostName.b [#MAX_HOSTNAME_LEN + 4]
	DomainName.b [#MAX_DOMAIN_NAME_LEN + 4]
	*CurrentDnsServer
	DnsServerList.IP_ADDR_STRING
	NodeType.l
	ScopeId.b [#MAX_SCOPE_ID_LEN + 4]
	EnableRouting.l
	EnableProxy.l
	EnableDns.l
EndStructure

fisize = SizeOf (FIXED_INFO)

*fi.FIXED_INFO = AllocateMemory (fisize)

valid = #False

Repeat

	Select GetNetworkParams_ (*fi, @fisize)

		Case #ERROR_SUCCESS
		
			valid = #True
				
		Case #ERROR_BUFFER_OVERFLOW

			*fi = ReAllocateMemory (*fi, fisize)
			
		Case #ERROR_INVALID_PARAMETER

			Debug "Epic fail! Invalid parameter passed to GetNetworkParams function..."
			End
	
		Case #ERROR_NO_DATA
	
			Debug "Epic fail! No data, whatever that means..."
			End

		Case #ERROR_NOT_SUPPORTED
	
			Debug "Epic fail! Not supported, whatever that means..."
			End

			Debug "Epic fail! Try calling GetError for more information..."
			End

		Default
		
	EndSelect

Until valid

If *fi\HostName
	Debug "Hostname: " + PeekS (@*fi\HostName)
EndIf

If *fi\DomainName
	Debug "Part of domain: " + PeekS (@*fi\DomainName)
EndIf

*dns.IP_ADDR_STRING = *fi\DnsServerList

dnscount = 0

While *dns

	dnscount = dnscount + 1
	
	Debug "DNS server " + Str (dnscount) + ": " + PeekS (@*dns\IpAddress)

	If *dns\IpMask
		Debug "Subnet mask: " + PeekS (@*dns\IpMask)
	EndIf

	*dns = *dns\Next
	
Wend

If *fi\NodeType

	Select *fi\NodeType
		Case #BROADCAST_NODETYPE
			node$ = "Broadcast"
		Case #PEER_TO_PEER_NODETYPE
			node$ = "Peer to peer"
		Case #MIXED_NODETYPE
			node$ = "Mixed"
		Case #HYBRID_NODETYPE
			node$ = "Hybrid"
	EndSelect

	Debug "Node type: " + node$

EndIf

If *fi\ScopeId
	Debug "Scope ID: " + PeekS (@*fi\ScopeId)
EndIf

If *fi\EnableRouting
	Debug "Routing: " + Str (*fi\EnableRouting)
EndIf

If *fi\EnableProxy
	Debug "Proxy: " + Str (*fi\EnableProxy)
EndIf

If *fi\EnableDns
	Debug "DNS: " + Str (*fi\EnableDns)
EndIf	

FreeMemory (*fi)

End
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Post Reply