Performing Actions in Our Session

We've made our connect call, but much like after our find hosts call, we don't really know what the outcome of that call was. Naturally, there is an event to handle this as well. Add the following handler to our InitializeDirectPlay method:

 connection.ConnectComplete += new     ConnectCompleteEventHandler(OnConnectComplete); 

We also need the event handler method implementation, so add this as well:

 private void OnConnectComplete(object sender, ConnectCompleteEventArgs e) {     // Check to see if we connected properly     if (e.Message.ResultCode == ResultCode.Success)     {         this.BeginInvoke(new AddTextCallback(AddText),             new object[] { "Connect Success." });         connected = true;         this.BeginInvoke(new EnableCallback(EnableSendDataButton),             new object[] { true } );     }     else     {         this.BeginInvoke(new AddTextCallback(AddText), new object[] {             string.Format("Connect Failure: {0}", e.Message.ResultCode) });         connected = false;         this.BeginInvoke(new EnableCallback(EnableSendDataButton),             new object[] { false } );     } } 

So this is where we can check to see if our connection call actually succeeded. The result code will tell us the result of the operation, and if that was a success, we've been connected to the session. In this case, we want to update our UI, and enable the send data button. If the connect call failed, we still update our UI; however, instead we disable the send data button, and set our connected variable to false. Setting this to false allows the FindHosts handler to try to connect to other sessions that it finds. You'll also notice that we don't have the delegate to enable or disable our send data button declared. You can declare it as follows:

 private delegate void EnableCallback(bool enable); 

You can run two instances of the application now and get them to connect to one another and be joined in the same session. On the first instance, click the Host button, and it should inform you that you are currently hosting the session. You can click the Connect button on the second instance, and after the dialog asking you about the remote host, you should see that it found your session and connected to it.

What we need now is a way to actually send some type of data to the session. We already have our send data button that currently doesn't do anything, so let's add this event handler for it:

 private void button3_Click(object sender, System.EventArgs e) {     NetworkPacket packet = new NetworkPacket();     packet.Write(byte.MaxValue);     connection.SendTo((int)PlayerID.AllPlayers, packet,         0, SendFlags.Guaranteed); } 

When sending data to a session in DirectPlay, it is common to use a network packet. You can write any information into this packet you want, providing it is a value type, an array of value types, or a string. You cannot pass in reference types to this method. We don't really care what we pass in for this application; we just want to send some value, so we'll just send in a single byte.

The actual send call is relatively straightforward. The first parameter is the player identifier of the user we want to send the data to. You can use any player or group identifier you wish, or (as we've done here) send it to all players. Don't worry; we'll discuss groups later. We naturally will also want to specify the network packet we will be sending. The third parameter is the timeout value for this packet. Values of zero (like we pass here) will never time out, unless of course the session itself drops. The last parameter we use for this call is one or more members of the SendFlags enumeration. Valid values for this enumeration are in Table 18.4:

Table 18.4. Possible SendFlags Values

VALUE

DESCRIPTION

Sync

Change the default behavior of this method from asynchronous operation to synchronous operation.

NoCopy

This flag is only valid on the overloads that accept the GCHandle structure as the network packet. This GCHandle must be allocated and pinned for this flag to be used. This will allow DirectPlay to use the data in the GCHandle directly, without making a separate copy. You may free the GCHandle on the SendComplete event. This flag cannot be used with the NoComplete flag.

NoComplete

Using this flag will cause the SendComplete event not to be fired. You may not use this flag if the NoCopy or Guaranteed flag is used.

CompleteOnProcess

When using this flag, the SendComplete event will only fire once the target connections receive method has processed the data. Normally, this event will fire as soon as the data is sent, but before the receiving connection has processed the message. Using this flag will add some extra overhead to the packet being sent. You must also use the Guaranteed flag when using this flag.

Guaranteed

Sends this message by a guaranteed method of delivery. Unless, of course, the connection is dropped.

PriorityHigh

Sends this message with a high priority. Cannot be used when you specify PriorityLow as well.

PriorityLow

Sends this message with a low priority. Cannot be used when you specify PriorityHigh as well.

NonSequential

The default behavior of DirectPlay is for messages to be received in the same order in which they were sent. If the messages arrive at the computer out of order, they will be buffered and re-ordered until DirectPlay has the ability to deliver them sequentially. Specifying this flag changes this default behavior and allows the messages to be delivered in the same order they arrive in.

NoLoopBack

Specifying this flag will cause the receive data event not to be fired when you're sending to a player or group that includes your local player.

Coalesce

Using this flag will allow DirectPlay to combine packets when sending.

As you can infer from the comments on the NoCopy flag, there are several overloads that take a GCHandle and buffer size variables. Since this is an asynchronous method, there are also overloads that return the asynchronous handle via an out parameter. Some of the overloads also include an application-defined context variable as well.

Now that data is being sent when we click our button, we will obviously need to include an event handler for when the data is received. Add this with the rest of the event hooks:

 connection.Receive += new     ReceiveEventHandler(OnDataReceive); 

Here is the code for the actual event handler:

 private void OnDataReceive(object sender, ReceiveEventArgs e) {     // We received some data, update our UI     string newtext = string.Format         ("Received message from DPlay UserId: 0x{0}",         e.Message.SenderID.ToString("x"));     this.BeginInvoke(new AddTextCallback(AddText),         new object[] { newtext }); } 

For this simple application, we don't actually care what the data we've received is, although we can get it from the ReceiveEventArgs object. Instead, we will just get the DirectPlay user identifier and update our UI to notify the user that a message was received.

Get two different instances of the application running (either on the same machine or on separate machines, it really doesn't matter). Have one be the host, while the other connects to it. Clicking the Send Data button should update the UI on both the sender as well as the receiver. This happens because we did not pass in the NoLoopBack flag when we called our SendTo method. The data is sent to everyone, including you.

Now, try this. While both instances are still running, quit the session that is the host. Now click the Send Data button on the remaining instance. You'll notice that an unhandled exception has occurred, which will cause your application to crash.



Managed DirectX 9 Graphics and Game Programming, Kick Start
Managed DirectX 9 Kick Start: Graphics and Game Programming
ISBN: B003D7JUW6
EAN: N/A
Year: 2002
Pages: 180
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net