Create a graphical alternative to NET SEND using the Win32 network API

\[Editor's Note: VB Solutions is about using Visual Basic (VB) to build a variety of solutions to specific business problems. This column doesn't teach you how to write VB, but how to use VB as a tool to provide quick, easy-to-implement solutions that you can use right away.\]

Windows NT's NET SEND command provides a useful way to send network messages; however, you have to run it from the NT command prompt. This month, I present an alternative to NET SEND that lets you send network messages without leaving NT's graphical interface. The NetMessage Visual Basic (VB) utility is a graphical equivalent of NET SEND. Instead of going to the NT command prompt, you can simply run NetMessage from your NT desktop or from the Start menu. Screen 1, page 184, shows the primary interface for NetMessage.

Using NetMessage is easy. The utility prompts you for the name to send a network message to and provides a multiline text box in which you enter the message's text. To send a message to a networked system, you enter the destination user's system name or logon name in the To box. NetMessage lets you either manually enter the name or select it from a drop-down box. You can also send a broadcast message to all users in your domain or other domains by selecting the domain name from the drop-down box, as shown in Screen 2, page 184, or by entering it manually. After entering the recipient's name and message text, you click Send to send the message. Screen 3, page 184, shows an example of the resulting pop-up message displayed on the target system.

The target system must be running the NT Messenger service to receive and display a network message. NT's Messenger service is started by default in most NT installations. The NetMessage utility sends the message via NetBIOS as the network transport.

Inside NetMessage
Now that you've seen how NetMessage works, let's build it. Because the NetMessage utility performs network calls, you might think building it requires complicated C communications coding and a knowledge of system internals. Not true. NT provides a rich set of network APIs, and you can call most of them from VB. By calling these APIs, your VB programs can access a variety of networking functions unavailable in standalone VB. The NetMessage utility uses NT's Win32 network API to handle the networking parts of the application.

The Win32 network API is in NT's netapi32.dll. This DLL contains many functions, but the NetMessage utility uses only three of them: NetServerEnum, NetWkstaGetInfo, and NetMessageBufferSend. Like several other VB Solutions utilities, NetMessage uses NetServerEnum to retrieve a list of networked systems--specifically, a list of all NT systems in the network. The NetWkstaGetInfo function retrieves the names of the network domain and local system--both of which are required to send a message across the network. The NetMessageBufferSend function sends a message across the network.

Because the functions contained in netapi32.dll are not built into VB, you must declare them before you can use them. (I explained the NetServerEnum function in the November 1996 VB Solutions column). The VB declaration for the NetWkstaGetInfo function is

Declare Function NetWkstaGetInfo _

Lib "Netapi32"

(ByVal sServerName$, _

ByVal lLevel&, vBuffer As Any) _

As Long

NetWkstaGetInfo is a fairly simple function that takes only three parameters. The first parameter is a Unicode string that contains the name of the server on which the function will be executed. A null string specifies that the function will run on the local system. The second parameter determines the level of information the function will return. NetWkstaGetInfo returns several different types of information depending on the value you specify in this parameter. However, the NetMessage utility uses only the most basic information, specified by passing the value 100. The third parameter is a pointer to a buffer that contains a data structure filled with the network information that corresponds to the information level specified by the second parameter.

The VB declaration for the NetMessageBufferSend function is

Declare Function _NetMessageBufferSend _Lib "Netapi32"_

(ByVal sServerName$, _

ByVal sMsgName$, _

ByVal sFromName$, _

ByVal sMessageText$, _

ByVal lBufferLength&) _

As Long

The NetMessageBufferSend function's first four parameters take Unicode strings. The first parameter contains the name of the server on which the function will be executed. The second parameter contains the message recipient's name. The third parameter contains the message sender's name. The fourth parameter contains the text of the message to be sent. The fifth parameter, a long integer, identifies the length of the message to be sent.

Because the NetMessageBufferSend function is declared in a DLL, all the string parameters are declared with the ByVal keyword. Although ByVal ordinarily causes VB to pass a parameter's value, this keyword works differently for passing string parameters to an external DLL such as netapi32.dll. Using ByVal to pass strings to functions contained in external DLLs causes VB to convert the strings from VB string format into the C string format required by most DLLs, including netapi32.dll. The fifth parameter also uses the ByVal keyword, but because this parameter contains a numeric variable and not a string, ByVal works as you'd expect: It causes VB to pass the value of the numeric variable, rather than passing a pointer to the variable.

Get the Message
Now that you've seen the Win32 Network API functions that NetMessage uses, let's see how the program uses them. The Form_Load event is the first piece of code NetMessage executes. Listing 1 shows the Form_Load subroutine.

Form_Load prepares the NetMessage utility to run. At callout A in Listing 1, Form_Load first creates a VB collection and then fills that collection with the network system names. These names are returned by the GetNetworkSystemNames function. (This function is a slightly revised version of the GetServerInfo function I used in prior VB Solutions. Besides GetNetworkSystemNames having a more descriptive name, the only difference between the old and new functions is that GetNetworkSystemNames accepts an argument that specifies the type of system to return and then returns a collection with the names of the networked systems.) The names in the collection are then added to the drop-down box displayed in Screen 2.

After the names of the networked systems are returned, Form_Load calls function GetDomainName to retrieve the network domain name that's added to the bottom of the list displayed in the drop-down box. At B in Listing 1, notice that the domain name has an appended asterisk. The NetMessageBufferSend function can use this special value (domainname*) to send broadcast messages to all systems in a domain.

Listing 2 shows how the GetDomainName function works. At A in Listing 2, GetDomainName calls the NetWkstaGetInfo function. NetWkstaGetInfo can return a variety of information about a local system's network connection. Here, the value 100 in the second parameter tells the NetWkstaGetInfo function to return the WKSTA_INFO_100 structure shown in Listing 3, page 186.

After the call to NetWkstaGetInfo is successfully completed, the WKSTA_INFO_100 structure is filled with data. The first field in this structure specifies the information level for retrieving platform-specific information. The second field contains the local computer name. Although the GetDomainName function doesn't use this field now, a later call retrieves this information. The third parameter contains the network domain name--the information you want the GetDomainName function to retrieve. The last two fields return the version number of the NT networking support that the local system uses.

At B in Listing 2, GetDomainName processes the information returned by NetWkstaGetInfo. Because NetWkstaGetInfo returns a pointer, you must use the native Win32 RtlMoveMemory API call to copy the data from the location identified by the pointer to the corresponding storage area defined by the twkstaInfo100 user-defined data type.

From there, GetDomainName retrieves the wki100_langroup field (which contains the domain name) from the WKSTA_INFO_100 structure. Because the Win32 network API functions return data only in Unicode format, the code at C in Listing 2 extracts every other byte from the string that contains the domain name. After extracting the ASCII portion of the domain name, the GetDomainName function returns the domain name to the calling routine--in this case, NetMessage's Form_Load subroutine.

Back in Form_Load, at B in Listing 1, the domain name and its special asterisk suffix are added to the bottom of the list of network system names that will appear in the drop-down box. The NetMessage program then displays the main window.

After selecting or entering the target system or network username and entering the message text, the user clicks Send to send the message. Listing 4 contains the code that handles the Send button's click event, the Command_Send_Click subroutine.

Send the Message
Command_Send_Click is where the real action takes place in the NetMessage utility. Command_Send_Click takes the target message name and the message text data that you entered in the main window and then calls the NetMessageBufferSend function to send the message across the network.

To send a message, NetMessageBufferSend requires three pieces of information: the name of the target user or system, the message text, and the name of the system sending the message. The target system name and message text come from the main window. Command_Send_Click uses the GetLocalSystemName function to dynamically retrieve the sending system name at A in Listing 4.

The GetLocalSystemName function, shown in Listing 5, works much like the GetDomainName function. Both functions call the NetWkstaGetInfo function to retrieve the required network information, and both use the WKSTA_INFO_100 data structure to return network data.

The primary difference between these two functions is the information each retrieves from the WKSTA_INFO_100 structure. Whereas GetDomainName returns WKST_INFO_100's third field (wki100_langroup), GetLocalSystemName returns the second field (wki100_computername), which contains the local system name. Just like GetDomainName, GetLocalSystemName extracts every other byte from the Unicode string and then returns the extracted system name to the calling routine--NetMessage'sCommand_Send_Click subroutine.

At A in Listing 4, you can see that the StrConv function uses the value that GetLocalSystemName returns. StrConv is a built-in VB function that converts VB strings to various formats, including Unicode. When you work with the Win32 network API functions, you must be aware of one gotcha: You must submit all string parameters in Unicode. Although most of the Win32 API set supports dual APIs, one for ASCII and one for Unicode, the Win32 network API functions support only Unicode strings.

Readers who are familiar with VB may think, "No problem. VB 4.0 already uses Unicode internally, so I don't have to do anything." Wrong. Although VB 4.0 uses Unicode internally, when VB 4.0 calls external functions, it automatically (maliciously?) converts all strings to ASCII. To pass Unicode values to external functions, I first use the StrConv function to explicitly convert each VB string to Unicode at B in Listing 4.

The Final Stretch
Finally, at C in Listing 4, the NetMessage utility calls the NetMessageBufferSend function to send the network message. The first parameter is a null string that forces NetMessageBufferSend to be executed on the local system. The second, third, and fourth parameters are Unicode strings containing the destination name, sending system name, and message text, respectively. The fifth parameter contains the length of the message text.

After NetMessageBufferSend finishes executing, subroutine Command_Send_Click checks the return code for a successful completion and displays the send status in NetMessage's main window.

The Power of the Win32 Network API Functions
Taking advantage of a few NT network API functions let me create a simple VB utility for sending impromptu messages across a network. To learn about the Win32 API and network API functions, refer to the Win32 Software Development Kit (SDK) in the Microsoft Developer's Network CD-ROM. Look for more VB solutions that you can put to work to solve some common problems your business faces.