Network functions please...

Blitz3D Forums/Blitz3D Programming/Network functions please...

Would someone show me how to search for network games, so I can have an in-game list of available games instead of having to use the window StartNetGame() pops up.

A few functions that see what connections a computer has - like the functions that tell blitz what graphics cards a computer has.
Functions for looking through all the games currently available on the desired connection type - kinda like the ones for searching the graphics modes or files in a directory.

That way, my game can just provide a list of possible games to join and let the user choose. And the player never has to type in anything but the name of the game he is creating. He doesn't have to watch as the cool graphics disappear and a stupid StartNetGame() window appears. The network is handled behind the scenes.

Obviously, StartNetGame() uses some functions to get the information I want, but I can't find anything in blitz to get that information.

Anybody have code or share my frustrations?

There are 3 protocols you can use to write multiplayer games: directplay, tcp and udp. It seems you want to use directplay. I have no idea about that one. You maybe want to use the free version of BLitzPlay instead, a UDP library. There is also a version of the PHP script GNET for BlitzPlay (GNet see this page menu). GNET will host IPs etc. of running games on a webserver, exactly what you want.

Yup, I've been down this lane. What you are looking for is a static server to keep all the information on available servers. Including IP's, Ping, COnnection Type, version, etc. etc. Sort of like what GameSpy Arcade is for major titles.

Gnet is Blitz's miniscule version. It will save Game Names, Server Names, and IP's only. You then use the Include functions to get that data to your game. Gnet will work for you, unless your talking about needing to host a ton of servers. Like any major online game (Halo, AA, etc.)

I use TCP and Gnet, if I had time or money, I would start my own site for hosting this info for games. Could make money to.

I can't seem to find GNet anywhere. Can someone provide a link?

[EDIT] Found GNet. Forgot the link like everyone else seems to have. Besides, what I'm looking for is LAN stuff, I'm not ready to make online games yet. GNet is a Blitz game server that allows blitz games to connect to a central online server (www.blitzbasic.com/gnet/gnet.php) so other players can join or host online games.
I don't think I want to use GNet. It was a good suggestion though. Thanks for the effort.

What I want to know is how StartNetGame() is obtaining a list of games, updating that list, and obtaining a list of possible connection types (TCP/IP, IPX, modem, serial, etc.). How does it get this infomation? Is it some DX thing? or is it part of windows? How does it get the information?

Any more ideas out there? code, userlibs, something...

DirectPlay is part of DX, but I don't care whether it's DX or windows or native blitz. Just show me how to do it in B3D and I'll be happy.

I need something to tell my program all the known connection types (TCP/IP, IPX, etc). Then, once my program choses the connection type, something to list all games on that connection type WITHIN my program, however I want to display the list, NOT in that stupid StartNetGame() window. I do not want to have to type in an IP address every time I join a game, I want to be able to just choose a game and join. And I want this for a LAN not an online game.
(yea, yea, I said the same thing over and over didn't I)

What do you mean by "LAN" ?
local ? or just Tcp/Ip ?

if you want LAN game, you'll have to specify the Ip ...
if you run locally with your fammily reseau, i d'ont know what will you call to receive informations. Unless you get datas from a server, and here, you'll have to get out from your local connection

If you want to play with lan using Tcp and an other player on the web, you could have a database MySql you log and had a party/Ip/name of the party ... etc... It will be your server ! Then, just have to call the database to receive informations.

Don't know if you use MySql, but it should be the best way !

You don't understand do you, Bobysait.

LAN - Local Area Network
TCP/IP - Transmission Control Protocol/Internet Protocol

TCP/IP is the standard protocol for network and online connections. Other protocols exist, like IPX, which is outdated.

It is NOT required to input an IP address, if you want proof, make a simple network program that inits using StartNetGame(). You will NEVER have to give ANY address information, no IP address, no computer name, no nothing, and yet you can still see all the games availiable on your network. I am on a network not connected to the internet. Besides, if I want a game between computer in my house, I don't want to send my game off to some server site just to get information that StartNetGame() gets without being online. Just play Warcraft III on you local network. Nowhere do you give it any IP information. You just click on the multiplayer button and it shows a list of all open games. I want to be able to do that kind of thing. I would like StartNetGame() to be broken into several function that don't have a stupid window. I don't know how or where StartNetGame() is getting the network information, but it is getting it and I want to know how.

Maybe Mark has some hints...

You need an enumeration routine...and there's just the function available in netapi32.dll. Here is the VB form:
Private Declare Function NetServerEnum Lib "netapi32" _
(ByVal servername As Long, _
ByVal level As Long, _
buf As Any, _
ByVal prefmaxlen As Long, _
entriesread As Long, _
totalentries As Long, _
ByVal servertype As Long, _
ByVal domain As Long, _
resume_handle As Long) As Long

if you want to see an example of this call in use, go to:
http://vbnet.mvps.org/index.html?code/network/netserverenum.htm

Hope this helps.
Kevin

Look promising...I'll post the Blitz code if it works...

Here is an interesting site that has a free network library that you can use with Blitz3d.
http://www.krylarskreations.com/knl.shtml

Kevin

Wow a livesign of Krylar! The Library looks good, tho:

"You'll shave MONTHS off of your multiuser development cycle!"

Well, not sure if my beard is really that large. :o)

at LEAST months. I was checking out the library and it looks like just what Subirenihil was wanting.

[EDIT] This what happens when you don't read the documentation and expect the demos to show everything! Read to the bottom of this to see how to connect without any IP stuff.

Krylar looked great - until I tried to connect to the host. It needed me to input an IP address - exactly what I am trying to avoid. Like I keep saying, StartNetGame() is the only way I've found to avoid that, but it pops up a stinking window and when I'm running a fullscreen game the window is hidden, making it look like the game locked up (it doesn't lock up, its just waiting for StartNetGame(), which isn't going do anything until I exit the fullscreen so the user can see the StartNetGame() menu and choose something, which exiting fullscreen frees all my loaded images, so I have to reload them once I return to fullscreen, which is REALLY annoying.

I'm working on that netapi32.dll stuff but I'm not doing something right. Anyone know how to do this with blitz?

These are the things I have ported into blitz. Does anyone know about writing .decls? I have something wrong here, but I'm not sure whether it is in the .decls or in my code. Please debug.
(Kevin8084, The net.bb is mostly the same your link went to ported to blitz. I ported the .decls came from there too. I've never ported anything before, so I'm sure its full of bugs)

----- netapi32.decls -----
.lib "netapi32.dll"
NetServerEnum%(servername%, level%, buf%, prefmaxlen%, entriesread%, totalentries%, servertype%, domain%, resume_handle%):"NetServerEnum"
NetApiBufferFree%(buffer%):"NetApiBufferFree"

----- net.bb -----
;Windows Type used To call the Net API
Const MAX_PREFERRED_LENGTH% = -1
Const NERR_SUCCESS% = 0
Const ERROR_MORE_DATA% = 234

Const SV_TYPE_WORKSTATION% = $1
Const SV_TYPE_SERVER% = $2
Const SV_TYPE_SQLSERVER% = $4
Const SV_TYPE_DOMAIN_CTRL% = $8
Const SV_TYPE_DOMAIN_BAKCTRL% = $10
Const SV_TYPE_TIME_SOURCE% = $20
Const SV_TYPE_AFP% = $40
Const SV_TYPE_NOVELL% = $80
Const SV_TYPE_DOMAIN_MEMBER% = $100
Const SV_TYPE_PRINTQ_SERVER% = $200
Const SV_TYPE_DIALIN_SERVER% = $400
Const SV_TYPE_XENIX_SERVER% = $800
Const SV_TYPE_SERVER_UNIX% = SV_TYPE_XENIX_SERVER
Const SV_TYPE_NT% = $1000
Const SV_TYPE_WFW% = $2000
Const SV_TYPE_SERVER_MFPN% = $4000
Const SV_TYPE_SERVER_NT% = $8000
Const SV_TYPE_POTENTIAL_BROWSER% = $10000
Const SV_TYPE_BACKUP_BROWSER% = $20000
Const SV_TYPE_MASTER_BROWSER% = $40000
Const SV_TYPE_DOMAIN_MASTER% = $80000
Const SV_TYPE_SERVER_OSF% = $100000
Const SV_TYPE_SERVER_VMS% = $200000
Const SV_TYPE_WINDOWS% = $400000 ;Windows95 And above
Const SV_TYPE_DFS% = $800000 ;Root of a DFS tree
Const SV_TYPE_CLUSTER_NT% = $1000000 ;NT Cluster
Const SV_TYPE_TERMINALSERVER% = $2000000 ;Terminal Server
Const SV_TYPE_DCE% = $10000000;IBM DSS
Const SV_TYPE_ALTERNATE_XPORT% = $20000000;rtn alternate transport
Const SV_TYPE_LOCAL_LIST_ONLY% = $40000000;rtn Local only
Const SV_TYPE_DOMAIN_ENUM% = $80000000
Const SV_TYPE_ALL% = $FFFFFFFF

Const SV_PLATFORM_ID_OS2% = 400
Const SV_PLATFORM_ID_NT% = 500

;Mask applied To svX_version_major in
;order To obtain the major version number.
Const MAJOR_VERSION_MASK% = $F

Type SERVER_INFO_100
Field sv100_platform_id%
Field sv100_name%
End Type

;Declare Function NetServerEnum Lib "netapi32" _
; (ByVal servername As Long, _
; ByVal level As Long, _
; buf As Any, _
; ByVal prefmaxlen As Long, _
; entriesread As Long, _
; totalentries As Long, _
; ByVal servertype As Long, _
; ByVal domain As Long, _
; resume_handle As Long) As Long

;Declare Function NetApiBufferFree Lib "netapi32" _
; (ByVal Buffer As Long) As Long

;Declare Sub CopyMemory Lib "kernel32" _
; Alias "RtlMoveMemory" _
; (pTo As Any, uFrom As Any, _
; ByVal lSize As Long)

;Declare Function lstrlenW Lib "kernel32" _
; (ByVal lpString As Long) As Long

Global txt$
GetServers("")
Print txt$
WaitKey
End

Function Form_Load()

; Command1.Caption = "Net Server Enum"

End Function


Function Command1_Click()

; Call GetServers("")

End Function


Function GetServers%(sDomain$)

;lists all servers of the specified Type
;that are visible in a domain.

Local bufptr%=CreateBank(10024)
Local dwEntriesread%
Local dwTotalentries%
Local dwResumehandle%
Local se100.SERVER_INFO_100
Local success%
Local nStructSize%
Local cnt%

nStructSize = 8;LenB(se100)

;Call passing MAX_PREFERRED_LENGTH To have the
;API allocate required memory For the Return values.
;
;The call is enumerating all machines on the
;network (SV_TYPE_ALL); however, by Or'ing
;specific bit masks For defined types you can
;customize the returned Data. For example, a
;value of 0x00000003 combines the bit masks For
;SV_TYPE_WORKSTATION (0x00000001) And
;SV_TYPE_SERVER (0x00000002).
;
;dwServerName must be Null. The level parameter
;(100 here) specifies the Data structure being
;used (in this Case a SERVER_INFO_100 structure).
;
;The domain member is passed as Null, indicating
;machines on the primary domain are To be retrieved.
;If you decide To use this member, pass
;StrPtr("domain name"), Not the String itself.
success = NetServerEnum(0,100,bufptr,MAX_PREFERRED_LENGTH,dwEntriesread,dwTotalentries,SV_TYPE_ALL,0,dwResumehandle)

;If all goes well
If success = NERR_SUCCESS And success <> ERROR_MORE_DATA Then

;loop through the returned Data, adding Each
;machine To the list
For cnt = 0 To dwEntriesread - 1

;get one chunk of Data And cast
;into an SERVER_INFO_100 struct
;in order To add the name To a list
PokeInt bufptr, nStructSize * cnt,se100\sv100_platform_id
PokeInt bufptr, nStructSize * cnt+4,se100\sv100_name

Txt$=txt$+Chr$(13)+GetPointerToByteStringW(se100\sv100_name)

Next

End If

;clean up regardless of success
NetApiBufferFree(bufptr)

;Return entries as sign of success
Return dwEntriesread

End Function


Function GetPointerToByteStringW$(dwData%)

Local tmp$=""
Local tmplen%

If dwData <> 0 Then

tmplen = BankSize(dwData); * 2

If tmplen <> 0 Then
For a=0 To tmplen-1
tmp$=tmp$+Chr$(PeekByte(dwdata,a))
Next

End If

End If
Return tmp$
End Function

Curious: did you want to create a bank that size?

Here you have: Local se100.SERVER_INFO_100
Did you want se100.SERVER_INFO_100 = new SERVER_INFO_100?

Actually, the bank size 10024 was a remnant of an attempt to get it to work. I originally had it 1024.

I no longer need the se100. (the code above used to have it like you have it, but I changed it while attempting to fix the bug.)

The new code runs without errors, but I have no idea why success returns 87. I don't think it runs properly yet because it can't find any games - even when I start one on the same computer - and only returns a success of 87. The msdn page says that the "level" parameter for NetServerEnum needs to be 100 or 101, but either of those values causes a "memory access violation". Suggestions anyone?

Anybody know what & means on the end of VB numbers (ie 0&)?

Bug finders, get to work!

Here is my updated code, the .decls are the same:
;Windows Type used To call the Net API
Const MAX_PREFERRED_LENGTH% = -1
Const NERR_SUCCESS% = 0
Const ERROR_MORE_DATA% = 234

Const SV_TYPE_WORKSTATION% = $1
Const SV_TYPE_SERVER% = $2
Const SV_TYPE_SQLSERVER% = $4
Const SV_TYPE_DOMAIN_CTRL% = $8
Const SV_TYPE_DOMAIN_BAKCTRL% = $10
Const SV_TYPE_TIME_SOURCE% = $20
Const SV_TYPE_AFP% = $40
Const SV_TYPE_NOVELL% = $80
Const SV_TYPE_DOMAIN_MEMBER% = $100
Const SV_TYPE_PRINTQ_SERVER% = $200
Const SV_TYPE_DIALIN_SERVER% = $400
Const SV_TYPE_XENIX_SERVER% = $800
Const SV_TYPE_SERVER_UNIX% = SV_TYPE_XENIX_SERVER
Const SV_TYPE_NT% = $1000
Const SV_TYPE_WFW% = $2000
Const SV_TYPE_SERVER_MFPN% = $4000
Const SV_TYPE_SERVER_NT% = $8000
Const SV_TYPE_POTENTIAL_BROWSER% = $10000
Const SV_TYPE_BACKUP_BROWSER% = $20000
Const SV_TYPE_MASTER_BROWSER% = $40000
Const SV_TYPE_DOMAIN_MASTER% = $80000
Const SV_TYPE_SERVER_OSF% = $100000
Const SV_TYPE_SERVER_VMS% = $200000
Const SV_TYPE_WINDOWS% = $400000 ;Windows95 And above
Const SV_TYPE_DFS% = $800000 ;Root of a DFS tree
Const SV_TYPE_CLUSTER_NT% = $1000000 ;NT Cluster
Const SV_TYPE_TERMINALSERVER% = $2000000 ;Terminal Server
Const SV_TYPE_DCE% = $10000000;IBM DSS
Const SV_TYPE_ALTERNATE_XPORT% = $20000000;rtn alternate transport
Const SV_TYPE_LOCAL_LIST_ONLY% = $40000000;rtn Local only
Const SV_TYPE_DOMAIN_ENUM% = $80000000
Const SV_TYPE_ALL% = $FFFFFFFF

Const SV_PLATFORM_ID_OS2% = 400
Const SV_PLATFORM_ID_NT% = 500

;Mask applied To svX_version_major in
;order To obtain the major version number.
Const MAJOR_VERSION_MASK% = $F

Type SERVER_INFO_100
Field sv100_platform_id%
Field sv100_name%
End Type

;Declare Function NetServerEnum Lib "netapi32" _
; (ByVal servername As Long, _
; ByVal level As Long, _
; buf As Any, _
; ByVal prefmaxlen As Long, _
; entriesread As Long, _
; totalentries As Long, _
; ByVal servertype As Long, _
; ByVal domain As Long, _
; resume_handle As Long) As Long

;Declare Function NetApiBufferFree Lib "netapi32" _
; (ByVal Buffer As Long) As Long

;Declare Sub CopyMemory Lib "kernel32" _
; Alias "RtlMoveMemory" _
; (pTo As Any, uFrom As Any, _
; ByVal lSize As Long)

;Declare Function lstrlenW Lib "kernel32" _
; (ByVal lpString As Long) As Long

Global txt$
Print GetServers("")
Print txt$
WaitKey
End

Function Form_Load()

; Command1.Caption = "Net Server Enum"

End Function


Function Command1_Click()

; Call GetServers("")

End Function


Function GetServers%(sDomain$)

;lists all servers of the specified Type
;that are visible in a domain.

Local bufptr%;=CreateBank(10024)
Local dwEntriesread%
Local dwTotalentries%
Local dwResumehandle%
Local se100.SERVER_INFO_100=New SERVER_INFO_100
Local success%
Local nStructSize%
Local cnt%

nStructSize = 8;LenB(se100)

Local d1=CreateBank(8)
d2=CreateBank(Len(sdomain$))
For a=0 To Len(sdomain$)-1:PokeByte d2,a,Asc(Mid$(sdomain$,a+1,1)):Next
;Call passing MAX_PREFERRED_LENGTH To have the
;API allocate required memory For the Return values.
;
;The call is enumerating all machines on the
;network (SV_TYPE_ALL); however, by Or'ing
;specific bit masks For defined types you can
;customize the returned Data. For example, a
;value of 0x00000003 combines the bit masks For
;SV_TYPE_WORKSTATION (0x00000001) And
;SV_TYPE_SERVER (0x00000002).
;
;dwServerName must be Null. The level parameter
;(100 here) specifies the Data structure being
;used (in this Case a SERVER_INFO_100 structure).
;
;The domain member is passed as Null, indicating
;machines on the primary domain are To be retrieved.
;If you decide To use this member, pass
;StrPtr("domain name"), Not the String itself.
success = NetServerEnum(0,d1,bufptr,MAX_PREFERRED_LENGTH,dwEntriesread,dwTotalentries,SV_TYPE_ALL,d2,dwResumehandle)

;If all goes well
If ((success = NERR_SUCCESS) And (success <> ERROR_MORE_DATA)) Then

;loop through the returned Data, adding Each
;machine To the list
For cnt = 0 To dwEntriesread - 1

;get one chunk of Data And cast
;into an SERVER_INFO_100 struct
;in order To add the name To a list
PokeInt bufptr, nStructSize * cnt,PeekInt(d1,0);se100\sv100_platform_id
PokeInt bufptr, nStructSize * cnt+4,PeekInt(d1,4);se100\sv100_name

Txt$=txt$+Chr$(13)+GetPointerToByteStringW(PeekInt(d1,4));se100\sv100_name)

Next

End If

;clean up regardless of success
NetApiBufferFree(bufptr)

;Return entries as sign of success
Return dwEntriesread ;change this to "Return success" if you want to see what success returns

End Function


Function GetPointerToByteStringW$(dwData%)

Local tmp$=""
Local tmplen%

If dwData <> 0 Then

tmplen = BankSize(dwData); * 2

If tmplen <> 0 Then
For a=0 To tmplen-1
tmp$=tmp$+Chr$(PeekByte(dwdata,a))
Next

End If

End If
Return tmp$
End Function

Error code 87 = invalid parameter

Thanks kevin. That way I at least know why it doesn't return any servers.

no problem. Good luck on your coding!

How do I send it a pointer to an array of the SERVER_INFO_100 structure? Or shouldn't a bank work just fine?

The first two parameters need to be 0, 100. The remaining parameters still need to be debugged.

I just ran your code and got an error 124 (invalid level error)

An array is, itself, a pointer to the data type that the array holds, yes? I don't think that it's needed to do more than send it the array.

Yea, it did that to me once with the first code. It always gives me an 87 with the second code.

I'm tweeking the variables and the buf parameter. I'm always getting a "memory access violation" and crashing blitzcc. I'm so glad Mark separated the compiler from the editor:)

For error lookups, go here:
http://www.allapi.net/php/errlookup/errlookup.php

Very handy site!

I'll try that then.

You're in Montana, yes? Chess player?

Thanks for the error page.

Identifier "se100" may not be used this way.

Dim se100.SERVER_INFO_100(100);=New SERVER_INFO_100

success = NetServerEnum(0,100,se100,MAX_PREFERRED_LENGTH,dwEntriesread,dwTotalentries,SV_TYPE_ALL,0,dwResumehandle)

no problem...I'm glad that sites such as that exist!

Belgrade, MT

How'd you know I liked chess?

you ranked #6 in 2003 tournament. You were in 8th grade at the time :)

The identifier error is in the success line.

I think that you're going to get your code working today.

There were two chess tournaments i entered in 2003 (those were the only tournaments I have ever entered, more recent ones have coincided with other more important events in my life so I haven't gotten a chance to enter) one on May 3, the other was on September 27. I think I got 4rth in May, just 'cause I was nervous and let a little kid pull a seven move checkmate on me:( My little brother took first in the level beneath me. I had moved up into the next level as had all the other good chess players. My best friend won first.

What place did you get in the tournament?

In May, Ben Darling took 1st place. Is this your best friend? The kid pulled the 7 move checkmate on you in Round 3, yes?

I didn't play. I haven't played chess in years (though I started when I was four years old LOL)

No, I didn't play Ben Darling in May. Some little 5th grader (that was the 7 move checkmate) was the only person I lost to that day. In September, Nathan Clevidence won. I think he won in May too, but he was in the 9th-12th range. Nathan is my best friend, haven't met Ben much other than at the chess tournaments.

Sorry about looking into your life a little. If you are curious, do a google search for "kevin8084" and for "klee8084". These are both me. You might find the reverse engineering aspects worthwhile. Now, gotta go for a while. Later!

(The 5th grader pulled the 7 move checkmate on me in round 1)

Back to topic.

How do you send an array to a function?

Just call the array inside of the function:

Dim a(10)

For x=0 To 9
a(x)=x
Next

doit()

WaitKey()
End

Function doit()

For x=0 To 9
Print a(x)
Next
End Function


Or, if you are worried about the scope, you can do this:

Global a[10]

For x=0 To 9
a[x]=x
Next

doit()

WaitKey()
End

Function doit()
For x=0 To 9
Print a[x]
Next
End Function


Um, I don't see how that works for the code.

If you find something that works, please tell me.

I just noticed that I need pointers (aka. banks) for some of the parameters instead of actual values. Success=0 (which is NERR_SUCCESS, which is exactly what you want to see). Everything seems to run great - UNTIL the program executes the End command, which causes a "Memory access violation"

Here's the new code (I have remove most of the commented code to make this a smaller post):

;Windows Type used To call the Net API
Const MAX_PREFERRED_LENGTH% = -1
Const NERR_SUCCESS% = 0
Const ERROR_MORE_DATA% = 234

Const SV_TYPE_WORKSTATION% = $1
Const SV_TYPE_SERVER% = $2
Const SV_TYPE_SQLSERVER% = $4
Const SV_TYPE_DOMAIN_CTRL% = $8
Const SV_TYPE_DOMAIN_BAKCTRL% = $10
Const SV_TYPE_TIME_SOURCE% = $20
Const SV_TYPE_AFP% = $40
Const SV_TYPE_NOVELL% = $80
Const SV_TYPE_DOMAIN_MEMBER% = $100
Const SV_TYPE_PRINTQ_SERVER% = $200
Const SV_TYPE_DIALIN_SERVER% = $400
Const SV_TYPE_XENIX_SERVER% = $800
Const SV_TYPE_SERVER_UNIX% = SV_TYPE_XENIX_SERVER
Const SV_TYPE_NT% = $1000
Const SV_TYPE_WFW% = $2000
Const SV_TYPE_SERVER_MFPN% = $4000
Const SV_TYPE_SERVER_NT% = $8000
Const SV_TYPE_POTENTIAL_BROWSER% = $10000
Const SV_TYPE_BACKUP_BROWSER% = $20000
Const SV_TYPE_MASTER_BROWSER% = $40000
Const SV_TYPE_DOMAIN_MASTER% = $80000
Const SV_TYPE_SERVER_OSF% = $100000
Const SV_TYPE_SERVER_VMS% = $200000
Const SV_TYPE_WINDOWS% = $400000 ;Windows95 And above
Const SV_TYPE_DFS% = $800000 ;Root of a DFS tree
Const SV_TYPE_CLUSTER_NT% = $1000000 ;NT Cluster
Const SV_TYPE_TERMINALSERVER% = $2000000 ;Terminal Server
Const SV_TYPE_DCE% = $10000000;IBM DSS
Const SV_TYPE_ALTERNATE_XPORT% = $20000000;rtn alternate transport
Const SV_TYPE_LOCAL_LIST_ONLY% = $40000000;rtn Local only
Const SV_TYPE_DOMAIN_ENUM% = $80000000
Const SV_TYPE_ALL% = $FFFFFFFF

Const SV_PLATFORM_ID_OS2% = 400
Const SV_PLATFORM_ID_NT% = 500

Const MAJOR_VERSION_MASK% = $F

Type SERVER_INFO_100
Field sv100_platform_id%
Field sv100_name%
End Type

Global txt$
Print GetServers("")
Print txt$
WaitKey
End

Function GetServers%(sDomain$)
Local bufptr%=CreateBank(1024)
Local dwEntriesread%=CreateBank(4)
Local dwTotalentries%=CreateBank(4)
Local dwResumehandle%
Local success%
Local nStructSize%
Local cnt%

nStructSize = 8;LenB(se100)

Local d1=CreateBank(1024)
d2=CreateBank(Len(sdomain$))
For a=0 To Len(sdomain$)-1:PokeByte d2,a,Asc(Mid$(sdomain$,a+1,1)):Next

success = NetServerEnum(0,100,bufptr,MAX_PREFERRED_LENGTH,dwEntriesread,dwTotalentries,SV_TYPE_ALL,0,dwResumehandle)
If ((success = NERR_SUCCESS) And (success <> ERROR_MORE_DATA)) Then

For cnt = 0 To PeekInt(dwEntriesread,0) - 1
Txt$=txt$+Chr$(13)+GetPointerToByteStringW(PeekInt(bufptr,cnt*nStructSize+4));se100\sv100_name)

Next

End If

NetApiBufferFree(bufptr)

Return PeekInt(dwEntriesread,0)

End Function


Function GetPointerToByteStringW$(dwData%)

Local tmp$=""
Local tmplen%

If dwData <> 0 Then

tmplen = BankSize(dwData); * 2

If tmplen <> 0 Then
For a=0 To tmplen-1
tmp$=tmp$+Chr$(PeekByte(dwdata,a))
Next

End If

End If
Return tmp$
End Function

This little example shows how to set up an array of types and shows that functions can access the array without being explicitly passed a pointer:
Type mytype
	Field x#,y#,z#
End Type

Dim cool.mytype(10)

doit()

WaitKey()
End

Function doit()
cool.mytype(0)=New mytype
cool(0)\x=5
Print cool(0)\x
delete cool(0)
End Function

Ahh...I see that you posted in the interim

Thanks for the code, but that's not quite what I had in mind. I was wanting to send the array of types out to the NetServerEnum - and it didn't like it.

Anyway, I figured out that my idea of using a bank was fine, the problem was that dwEntriesRead and dwTotalEntries needed to be banks too.

But there's still a problem with my code? The End statement causes a "Memory access violation"

I have to go offline for a bit. I will attempt to recreate your program from scratch and see if I come up with the same error...I'll post when the program is complete.

Kevin

So far I'm having the same luck as you...very frustrating

The NetServerEnum seems to be messing up the bank, so when Blitz tries to free it it causes an error.

Insert "FreeBank bufptr" anywhere after you create the bank. FreeBank will cause an error if you insert it after the NetServerEnum. If you insert it before the NetServerEnum, then End causes an error (because End cleans up everything, including freeing existing banks) I think it NetServerEnum may be using the wrong variable initialization command - I saw something somewhere about you must use a certain command for declaring variables when creating a dll. I will look at finding the windows command to create a bank that I can send to NetServerEnum.

This is looking very promising, but the task is a little more than I expected. I hope we can get this working so that future programmers can have a more professional style networking lib at their fingertips - and our names possibly in the credits.

Thanks for all your help Kevin. It has been a pleasure knowing someone that I can work with.

GRRRrrrrrr...

I think I need someone to write a dll to do this. I'd try, but I don't have anything but Blitz. This is a hint...

Microsoft gives out it's express edition for free. You can make dlls quite easily with the Visual C++ Express edition or Visual C# express edition.

Where do I get it at (I could search but why bother when you could tell me)?

[EDIT]
Here's the download link if anybody else is curious:
Express C++

You can also get the Visual Basic express edition and the Visual J# express edition. Needless to say, I have them all :)

In your code you can stop the error messages by:
While success=$234
success = NetServerEnum(0,100,bufptr,MAX_PREFERRED_LENGTH,dwEntriesread,dwTotalentries,SV_TYPE_ALL,0,dwResumehandle)
Wend

Simply continuing on receiving data from the function while there is still information.

Oooooooooooooh!

ERROR_MORE_DATA is supposed to be $234, not 234.

Thanks Kevin!

Now, to see if I can start a server.

no problem

Hey Kevin! I found out why adding those lines prevents the error. It SKIPS "success=NetServerEnum(0,100,..." for proof, insert a "Stop" inside the loop - the "Stop" will never get triggered.

I think you wanted to do something like this:
success=$234
While success=$234
success=NetServerEnum(0,100,bufptr,MAX_PREFERED_LENGTH,dwEntriesread,dwTotalentries,SV_TYPE_ALL,0,dwResumehandle)
Wend

Or like this:
Repeat
success=NetServerEnum(0,100,bufptr,MAX_PREFERED_LENGTH,dwEntriesread,dwTotalentries,SV_TYPE_ALL,0,dwResumehandle)
Until success=$234

BUT I FOUND I WAS WRONG ABOUT KNL!!!
I got it to work!

I'm on a different computer from my programming one so I can't post the code right now - I'll post as so as I can.

Thanks for all your help Kevin! You're definently going to be in the credits. I could try to send you a copy of of the game if you like - if/when I finish it. Thanks!

Glad to have helped, Subirenihil :)

Alright! I now have a program to demonstrate a no-IP network connection.

Step 1: Download and install the K-NetLib
K-NetLib

Step 2: Run this code on several computers on your network. (it's quite elaborate, but uncommented)
Type host
	Field ip$,gn$,cp%,mp%,tim%
End Type

Type player
	Field id%,name$
End Type

Type chat
	Field msg$,pos%
End Type

Graphics 640,480,0,2
SetBuffer FrontBuffer()
Cls
Locate 0,0
name$=Input$("What is your name? ")
SetBuffer BackBuffer()

KNL_Initialize("{24538F2F-748F-4779-8E20-36D948406E34}",8,134)

KNL_EnumerateHosts(8080)

k$=""
xit$=0
Repeat
	While KNL_CheckMessages()=-1
		id=KNL_GetMessageID()
		If id=31
			hip$=KNL_FieldGetString$("HostIP")
			newh=True
			For h.host=Each host
				If h\ip$=hip$
					newh=False
					h\gn$=KNL_FieldGetString$("HostName")
					h\cp%=KNL_FieldGetInteger("CurrentPlayers")
					h\mp=KNL_FieldGetInteger("MaxPlayers")
					h\tim%=MilliSecs()
				EndIf
			Next
			If newh=True
				h.host=New host
				h\ip$=hip$
				h\gn$=KNL_FieldGetString$("HostName")
				h\cp%=KNL_FieldGetInteger("CurrentPlayers")
				h\mp=KNL_FieldGetInteger("MaxPlayers")
				h\tim%=MilliSecs()
			EndIf
		EndIf
		KNL_ClearMessage
	Wend
	Repeat
		k1=GetKey()
		k2=GetKey()
		kx=True
		Select k1
			Case 0:
			Case 8:
				If Len(k$)>1 Then k$=Left$(k$,Len(k$)-1)
				If Len(k$)<=1 Then k$=""
				kx=False
			Case 9:
				kx=False
				k$=k$+"    "
			Case 13:
				c.chat=New chat
				c\msg$=k$
				c\pos%=1
				k$=""
				kx=False
			Default:
				If k1>=32 And k1<=126
					k$=k$+Chr$(k1)
					kx=False
				EndIf
		End Select
		Select k2
			Case 0:
			Case 8:
				If Len(k$)>1 Then k$=Left$(k$,Len(k$)-1)
				If Len(k$)<=1 Then k$=""
				kx=False
			Case 9:
				kx=False
				k$=k$+"    "
			Case 13:
				c.chat=New chat
				c\msg$=k$
				c\pos%=1
				k$=""
				kx=False
			Default:
				If k2>=32 And k2<=126
					k$=k$+Chr$(k2)
					kx=False
				EndIf
		End Select
	Until kx=True
	pos=1
	For h.host=Each host
		If h\cp<h\mp
			If KeyHit(58+pos) Then xit=h\ip$
			pos=pos+1
			c.chat=New chat
			c\msg$=h\gn$+" ("+Str$(h\cp)+"/"+Str$(h\mp)+")"
			c\pos%=2
		EndIf
		If MilliSecs()-h\tim>3000 Then Delete h
	Next
	pos=1
	
	Cls
	Text 0,0,"Open Games (press the corrosponding function to join a game):",0,0
	For c.chat=Each chat
		If c\pos=1
			xit=1
		ElseIf c\pos=2
			If pos<=11 Then Text 20,20*pos,c\msg,0,0
			pos=pos+1
			Delete c
		EndIf
	Next
	If MilliSecs() Mod 500 > 250 Then
		Text 0,240,"Create Game: "+k$+"|"
	Else
		Text 0,240,"Create Game: "+k$
	EndIf
	Flip
Until xit<>0
KNL_StopHostsEnumeration

Cls
Flip

If xit=1
	For c.chat=Each chat
		If c\pos=1 Then Exit
	Next
	Text 320,240,"Starting net game "+Chr$(34)+c\msg$+Chr$(34)+" ...",1,1
	Flip
	
	If KNL_CreateHost(8080,c\msg$,"","",8)=0
		Cls
		Text 320,240,"Failed to create host. Press a key.",1,1
		FlushKeys
		Flip
		WaitKey
		KNL_Shutdown
		End
	EndIf
	KNL_SetPlayerInfo name$,""
Else
	For h.host=Each host
		If h\ip$=xit$ Then Exit
	Next
	Text 320,240,"Connecting to net game "+Chr$(34)+h\gn$+Chr$(34)+" ...",1,1
	Flip
	
	KNL_Shutdown
	KNL_Initialize("{24538F2F-748F-4779-8E20-36D948406E34}",8,138)
	If KNL_Connect(name$,"",xit$,8080,"",1)=0
		Cls
		Text 320,240,"Failed to connect to host. Press a key.",1,1
		FlushKeys
		Flip
		WaitKey
		KNL_Shutdown
		End
	EndIf
EndIf

For c.chat=Each chat
	Delete c
Next

Cls

k$=""
Repeat
	While KNL_CheckMessages()
		Select KNL_GetMessageID()
			Case 28:
				pid%=KNL_FieldGetInteger("LocalID")
				p.player=New player
				p\id%=pid%
				p\name$=name$
			Case 3
				pid%=KNL_FieldGetInteger("LocalID")
				p.player=New player
				p\id%=pid%
				p\name$=name$
			Case 4:
				pid%=KNL_FieldGetInteger("PlayerID")
				p.player=New player
				p\id%=pid%
				p\name$=KNL_GetPlayerName$(pid)
				c.chat=New chat
				c\pos=2
				c\msg$=p\name$+" has joined the game."
			Case 5:
				pid%=KNL_FieldGetInteger("PlayerID")
				For p.player=Each player
					If p\id%=pid%
						c.chat=New chat
						c\pos=2
						c\msg$=p\name$+" has left the game."
					EndIf
					Delete p
				Next
			Case 7:
				Select KNL_GetInteger(0)
					Case 1:
						pid%=KNL_FieldGetInteger("SenderID")
						For p.player=Each player
							If p\id%=pid%
								c.chat=New chat
								c\pos=2
								c\msg$=p\name$+": "+KNL_GetString$(1)
							EndIf
						Next
				End Select
		End Select
		KNL_ClearMessage()
	Wend

	Repeat
		k1=GetKey()
		k2=GetKey()
		kx=True
		Select k1
			Case 0:
			Case 8:
				If Len(k$)>1 Then k$=Left$(k$,Len(k$)-1)
				If Len(k$)<=1 Then k$=""
				kx=False
			Case 9:
				kx=False
				k$=k$+"    "
			Case 13:
				c.chat=New chat
				c\msg$=k$
				c\pos%=1
				k$=""
				kx=False
			Default:
				If k1>=32 And k1<=126
					k$=k$+Chr$(k1)
					kx=False
				EndIf
		End Select
		Select k2
			Case 0:
			Case 8:
				If Len(k$)>1 Then k$=Left$(k$,Len(k$)-1)
				If Len(k$)<=1 Then k$=""
				kx=False
			Case 9:
				kx=False
				k$=k$+"    "
			Case 13:
				c.chat=New chat
				c\msg$=k$
				c\pos%=1
				k$=""
				kx=False
			Default:
				If k2>=32 And k2<=126
					k$=k$+Chr$(k2)
					kx=False
				EndIf
		End Select
	Until kx=True

	pos=0
	For c.chat=Each chat
		If c\pos=1
			d.chat=New chat
			d\msg$=name$+": "+c\msg$
			d\pos=2
			KNL_SendInteger 1
			KNL_SendString c\msg$
			KNL_UpdateNetwork(0,0,1000,2)
			Delete c
		Else
			pos=pos+1
		EndIf
	Next
	If pos>20
		c.chat=First chat
		For a=1 To pos-20
			d.chat=After c
			Delete c
			c=d
		Next
	EndIf
	pos=0
	Cls
	For c.chat=Each chat
		Text 0,pos*20,c\msg$,0,0
		pos=pos+1
	Next
	If MilliSecs() Mod 500 > 250 Then
		Text 0,420,"Chat: "+k$+"|"
	Else
		Text 0,420,"Chat: "+k$
	EndIf
	Flip
Until KeyHit(1)

KNL_Shutdown
End