Any idea why this fails on '98?

Everything else that doesn't fall into one of the other PB categories.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Hi-Toro.

Hi all,

I have a 2-PC network: my PC (Windows 2000) and my brother's (Windows 98SE). This code, when run on Windows 2000, correctly lists the computers and their IP addresses on the network. When I run it on my brother's '98 PC, though, it fails to get the information. I have checked all of the Win32 API commands I'm using and they should all work on '9x, but something's not quite right :/

One thing I have found is that if you change 'For entry = 1 To entries', in the section that lists the computers, to 'For entry = 0 To entries', you at least get partial information for one of the PCs.

Can anyone tell why this isn't working when run on '98? (:·O

Code: Select all

; -----------------------------------------------------------------------------
; List IP addresses of local network PCs -- james @ hi-toro.com
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; * * * * * ONLY WORKS WHEN RUN ON WINDOWS 2000...! :( * * * * *
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; SAMPLE OUTPUT:
; -----------------------------------------------------------------------------

;       Local network resources...

;       "FRANK" on "Microsoft Windows Network"                      ; A Windows98SE PC...

;           Host name: FRANK
;           IP address: 192.168.0.210

;       "SCORPIO" on "Microsoft Windows Network"                   ; This Windows 2000 PC...

;           Host name: scorpio
;           IP address: 192.168.0.1


;       Press ENTER...

; -----------------------------------------------------------------------------
; Structure not defined in PB (needed for gethostbyname function)...
; -----------------------------------------------------------------------------

Structure HOSTENT
 h_name.l
 h_aliases.l
 h_addrtype.l
 h_length.l
 h_addr_list.l
EndStructure

; -----------------------------------------------------------------------------
; Some constants not defined in PB...
; -----------------------------------------------------------------------------

#NO_ERROR = 0
#ERROR_NO_ERROR = 0
#ERROR_BAD_DEVICE = 1200
#ERROR_CONNECTION_UNAVAIL = 1201
#ERROR_EXTENDED_ERROR = 1208
#ERROR_MORE_DATA = 234
#ERROR_NOT_SUPPORTED = 50
#ERROR_NO_NET_OR_BAD_PATH = 1203
#ERROR_NO_NETWORK = 1222
#ERROR_NOT_CONNECTED = 2250

; -----------------------------------------------------------------------------
; Some error procedures...
; -----------------------------------------------------------------------------

; Used to set last error to 0 on startup (NEEDED!)...

Procedure InitErrors (default)
  SetLastError_ (default)
EndProcedure

; Retrieves last reported error in program...

Procedure GetLastError ()
  error = GetLastError_ ()
  If error
    AllocateMemory (0, 255)
    FormatMessage_ (#FORMAT_MESSAGE_FROM_SYSTEM, #NULL, error, 0, MemoryID (), 255, #NULL)
    e$ = PeekS (MemoryID ())
    FreeMemory (0)
    MessageRequester (title$, e$, #MB_ICONWARNING)
  EndIf
EndProcedure

; Retrieves last network error in program...

Procedure GetNetError ()
    error$ = Space (256)
    provider$ = Space (256)
    WNetGetLastError_ (code, error$, 256, provider$, 256)
    If error$ = Space (256)
        error$ = "Weird; there's no reported network error! Why am I here?!"
    EndIf
    MessageRequester ("Network error!", "A network error has occurred!" + Chr (10) + Chr (10) + error$, #MB_ICONWARNING)
EndProcedure

; -----------------------------------------------------------------------------
; MAIN PROGRAM...
; -----------------------------------------------------------------------------

; Reset the error system...

InitErrors (0)

; WSAStartup is needed before calling gethostbyname_ () further down...

; Version 1.1 of Windows Sockets needed...

high.b = 1
low.b = 1

DefType.w wsaversion
PokeB (@wsaversion, high)          ; Gotta poke major version number into low byte...
PokeB (@wsaversion + 1, low)     ; ... and minor version number into high byte

; WSAStartup returns 0 (no errors) if successful...

If WSAStartup_ (wsaversion, wsa.WSAData)
    MessageRequester ("Network error", "WSA startup failed!" + Chr (10) + Chr (10) + error$, #MB_ICONWARNING)
    End
EndIf

; Get a handle for retrieving a list of computers on local network...

error = WNetOpenEnum_ (#RESOURCE_CONTEXT, #RESOURCETYPE_DISK, 0, #NULL, @nethandle)

Select error

    Case #ERROR_NO_ERROR

        ; ---------------------------------------------------------------------
        ; START OF NETWORK PC LIST CODE...
        ; ---------------------------------------------------------------------

        ; No error, so let's see what we have here...
        
        OpenConsole ()

        PrintN ("")
        PrintN ("Local network resources...")
        PrintN ("")
        
        ; Default to a large number of PCs (thanks to M$, you MUST do it like this!)...
        
        check = 1024
        entries = -1
        size = SizeOf (NETRESOURCE) * check

        Dim network.NETRESOURCE (check)

        ; Read list of PCs into network.NETRESOURCE array...
        
        reserror = WNetEnumResource_ (nethandle, @entries, @network (), @size)

        If reserror = #NO_ERROR
                
                ; Read array for however many we found (WNetEnumResource pokes the number into 'entries')...
                
                For entry = 1 To entries

                    Select network (entry)\dwScope
                    
                        ; Dunno what this means exactly...
                        
                        Case #RESOURCE_CONNECTED
                            PrintN ("Resource connected")
                        
                        ; But this is the one we want...
                            
                        Case #RESOURCE_GLOBALNET
                        
                            ; Get network PC name and the type of network (eg. Microsoft Windows Network)...
                            
                            computer$ = PeekS (network (entry)\lpRemoteName)
                            networktype$ = PeekS (network (entry)\lpProvider)
                            
                            ; Strip off backslash prefix (eg. "\\YOURCOMPUTERNAME")...
                            
                            While Left (computer$, 1) = "\"
                                computer$ = Right (computer$, Len (computer$) - 1)
                            Wend

                            PrintN (Chr (34) + computer$ + Chr (34) + " on " + Chr (34) + networktype$ + Chr (34))

                            ; Get pointer to the host data for the network PC...
                            
                            *host.HOSTENT = gethostbyname_ (computer$)

                            If *host  #NULL
                            
                                ; Here we print the name and the IP address (hooray for inet_ntoa!)...
                                
                                PrintN ("")
                                PrintN ("   Host name: " + PeekS (*host\h_name))
                                PrintN ("   IP address: " +  PeekS (inet_ntoa_  (PeekL (*host\h_addr_list))))
                                
                            Else
                                GetLastError ()
                            EndIf
                        
                        ; Dunno about this either...
                            
                        Case #RESOURCE_REMEMBERED 
                            PrintN ("Resource remembered")
                            
                    EndSelect

                    PrintN ("")
                    
                Next
            
        EndIf
        
        PrintN ("Press ENTER...")
        Input ()

        CloseConsole ()
        
        ; We MUST free the handle we got for listing the network PCs...
        
        WNetCloseEnum_ (nethandle)
        
        ; ... and we also MUST clean up the WSA thing!
        
        WSACleanup_ ()

        ; ---------------------------------------------------------------------
        ; END OF NETWORK PC LIST CODE...
        ; ---------------------------------------------------------------------

    ; This stuff is the remainder of the first Select/EndSelect after WNetOpenEnum...
    
    Case #ERROR_NO_NETWORK
        MessageRequester ("Network error!", "There's no network here!", #MB_ICONWARNING)
        End

    Case #ERROR_EXTENDED_ERROR
        GetNetError ()
        End
     
    Default
        GetLastError ()

EndSelect

End

--
See ya,
James L Boyd.
http://www.hi-toro.com/
--
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tinman.
Originally posted by Hi-Toro
One thing I have found is that if you change 'For entry = 1 To entries', in the section that lists the computers, to 'For entry = 0 To entries', you at least get partial information for one of the PCs.
Wouldn't that be because PB arrays start from an index of 0?


--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + SP1, PB3.40)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Hi-Toro.
Wouldn't that be because PB arrays start from an index of 0?
Yeah, but if you print the contents of network (0) when running it on 2000, it prints... well... crap :)

So it looks like the information is poked into the array by Windoze from array offset 1 onwards...? If I print out '1 to entries', I get the correct information on 2000... but I still don't get why either method returns nothing (1 - entries) or only partial information (0 - entries) on '98 :(


--
See ya,
James L Boyd.
http://www.hi-toro.com/
--
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tinman.
Originally posted by Hi-Toro
Yeah, but if you print the contents of network (0) when running it on 2000, it prints... well... crap :)
OK, yeah, now that I'm home I've tested it and it doesn't work from 0. It doesn't get any of my network resources here (couple of Win98 machines).
So it looks like the information is poked into the array by Windoze from array offset 1 onwards...? If I print out '1 to entries', I get the correct information on 2000... but I still don't get why either method returns nothing (1 - entries) or only partial information (0 - entries) on '98 :(
Are you sure their networking is set up in a similar way? Perhaps there is something in the options that broke the code? Or maybe the Win2K networking is so much better than the Win98 stuff in that it works and does what it says in the API :wink:

Update: well I poked around a bit and it seems Windows does put something usable in the first array item (although it also claims it could only find one network resource, and is not too useful). It returns something like this in the first array item here:

Scope = globalnet (2)
type = all (0)
DisplayType = network (6)
usage = container (2)
Local name = 0
Remote name = 0
Comment = "Microsoft network"
Provider = "Microsoft network"

I also created a shared drive on the other machine, and tried mapping one of my local drives to it, but it did not change anything. However, I did fiddle with the open enum line to get this working.

I went back to your line (where did you find #RESOURCE_CONTEXT? It's not mentioned in my API docs?) and it still gives useful information in the first array item, but again not the kind of stuff you are looking for:

Scope = globalnet (2)
type = all (0)
DisplayType = root (7)
usage = container (2)
Local name = 0
Remote name = 0
Comment = "Entire network"
Provider = 0

The API docs I have here say you can use another round of net enumeration on container types. Perhaps you need to do this on older machines to get the full set of network info with proper NT based ones giving all information at once?

--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + SP1, PB3.40)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Hi-Toro.

Hi Tinman,

I found #RESOURCE_CONTEXT in various source codes I searched for on the net, then did a Google search for RESOURCE_CONTEXT and msdn :)

As for 'containers', I did read about those, but I didn't understand what exactly they referred to -- do you know what a container is here?


--
See ya,
James L Boyd.
http://www.hi-toro.com/
--
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tinman.
Originally posted by Hi-Toro
As for 'containers', I did read about those, but I didn't understand what exactly they referred to -- do you know what a container is here?
Not exact;y, but it looks like it is just a network resource which contains other network resources. For example, I should have been able to call the network enum stuff again after I found "Entire Network" to give me the computers on my network.

That's my guess, but there's nothing saying that it needs to match up with how Windows works :)

--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + SP1, PB3.40)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Hi-Toro.

Yeah, I think I get what you mean... I'll give it some more investigation later -- thanks :)


--
See ya,
James L Boyd.
http://www.hi-toro.com/
--
Post Reply