Microsoft DirectX 8.1 (C++)

Handling Standard Peer-to-Peer Messages

This document describes how to handle Microsoft® DirectPlay® messaging for a normal member of a peer-to-peer session. It does not discuss messages that are specific to a host. For a discussion of host-related messaging, see Peer-to-Peer Host Messages. For a discussion of general messaging issues, see Handling DirectPlay Messaging.

Startup Messages

The host can set up a peer-to-peer session in two ways.

This section describes the messages you may receive when selecting and joining a session.

DPN_MSGID_ENUM_HOSTS_RESPONSE
If you need to locate a standalone session, call IDirectPlay8Peer::EnumHosts to enumerate the available hosts. You will receive a DPN_MSGID_ENUM_HOSTS_RESPONSE message for each host that responds to your enumeration request. You may receive multiple DPN_MSGID_ENUM_HOSTS_RESPONSE messages from the same host.

By default, host enumeration is performed asynchronously. When an asynchronous enumeration terminates, for instance after the retry count is reached, you will be notified with a DPN_MSGID_ASYNC_OP_COMPLETE message. You will receive no further DPN_MSGID_ENUM_HOSTS_RESPONSE messages after DPN_MSGID_ASYNC_OP_COMPLETE arrives. You can cancel the operation at any time by calling IDirectPlay8Client::CancelAsyncOperation. You can also cancel a host enumeration by calling IDirectPlay8Peer::Connect to connect to a session. The enumeration is halted as soon as the connect request completes successfully.

Note You should call IDirectPlay8Peer::Connect outside of the DPN_MSGID_ENUM_HOSTS_RESPONSE message handler.

DPN_MSGID_CONNECT_COMPLETE
Typically, the next step you will take is to attempt to join a session by calling IDirectPlay8Peer::Connect. You normally receive a DPN_MSGID_CONNECT_COMPLETE message with the host's response, even if the host rejects your connection request. You can receive this message for asynchronous and synchronous calls, but there are differences in detail.

DPN_MSGID_CREATE_PLAYER and DPN_MSGID_CREATE_GROUP
If your connection attempt was successful, you will receive a DPN_MSGID_CREATE_PLAYER message for each player in the session at the time you joined. At a minimum, you will receive one message for the host and one for your player. If any groups have been created, you will receive a DPN_MSGID_CREATE_GROUP message for each group. You will also receive a series of DPN_MSGID_ADD_PLAYER_TO_GROUP messages for each group, one for each player in the group. All of these messages will arrive before DPN_MSGID_CONNECT_COMPLETE.

You must define your player and group context values when you handle the associated creation messages. These context values can also be defined earlier, when IDirectPlay8Peer::Host, IDirectPlay8Peer::Connect, or IDirectPlay8Peer::CreateGroup methods are called. You can change those player or group context values when you handle DPN_MSGID_CREATE_PLAYER or DPN_MSGID_CREATE_GROUP respectively. However, once that handler returns, the corresponding context value cannot be changed again. See Using Player Context Values for further discussion.

Messaging During Normal Game Play

During a game, you might receive any of the following messages.

DPN_MSGID_CREATE_PLAYER and DPN_MSGID_DESTROY_PLAYER
Players can typically enter or leave while the game is in progress. You receive a DPN_MSGID_CREATE_PLAYER when a player enters a game, and a DPN_MSGID_DESTROY_PLAYER message when that player leaves. You might receive DPN_MSGID_CREATE_PLAYER and DPN_MSGID_DESTROY_PLAYER messages simultaneously on different threads, but only for different players. You will not receive a DPN_MSGID_DESTROY_PLAYER message before your callback function has returned from receiving the corresponding DPN_MSGID_CREATE_PLAYER message. If you want to create a player context value, you must do so before you return from the DPN_MSGID_CREATE_PLAYER message handler.

DPN_MSGID_CREATE_GROUP and DPN_MSGID_DESTROY_GROUP
Many games simplify messaging by allowing players to be grouped. When a group is created, you receive a DPN_MSGID_CREATE_GROUP message, regardless of whether your player is a member. If you want to create a group context value, you must do so before you return from the DPN_MSGID_CREATE_GROUP message handler. When a group is destroyed, you receive a DPN_MSGID_DESTROY_GROUP message. You will not receive a DPN_MSGID_DESTROY_GROUP message before your callback function has returned from processing the corresponding DPN_MSGID_CREATE_GROUP message.

DPN_MSGID_ADD_PLAYER_TO_GROUP and DPN_MSGID_REMOVE_PLAYER_FROM_GROUP
You receive DPN_MSGID_ADD_PLAYER_TO_GROUP messages for each group member after a group is created, and when a player is added to a group. You receive a DPN_MSGID_REMOVE_PLAYER_FROM_GROUP message when a player is removed from a group, and for all the remaining players in the group when the group is destroyed. You will not receive a DPN_MSGID_REMOVE_PLAYER_FROM_GROUP message before your callback function has returned from processing the corresponding DPN_MSGID_ADD_PLAYER_TO_GROUP message.

You are guaranteed to receive every DPN_MSGID_REMOVE_PLAYER_FROM_GROUP message for a group before you receive the DPN_MSGID_DESTROY_GROUP message. When a player is destroyed, you will receive a DPN_MSGID_REMOVE_PLAYER_FROM_GROUP message for every group in which that player is a member, before you receive the player's DPN_MSGID_DESTROY_PLAYER message.

DPN_MSGID_SEND_COMPLETE
You send data to a player or group by calling IDirectPlay8Peer::SendTo. If you call this message asynchronously, the method will normally return DPNERR_PENDING. You receive a DPN_MSGID_SEND_COMPLETE message when the data is sent. The DPN_MSGID_SEND_COMPLETE message can arrive before or after the method returns.

Receiving a DPN_MSGID_SEND_COMPLETE message does not necessarily mean that the target has received and processed the message. By default, if the network is overloaded, packets may be dropped. If you want to be certain that the message has arrived at the target, set the DPNSEND_GUARANTEED flag when you call IDirectPlay8Peer::SendTo. You will not receive a DPN_MSGID_SEND_COMPLETE message until DirectPlay has verified that the target has received the data. If you want to be certain that the message has also been processed by the target, set the DPNSEND_COMPLETEONPROCESS flag. If you set this flag, you will not receive a DPN_MSGID_SEND_COMPLETE message until the target's message handler has processed the message and returned.

Note Setting the DPNSEND_GUARANTEED and DPNSEND_COMPLETEONPROCESS flags add overhead to the Send process. You may want to design your communication process to be able to tolerate some data loss in return for increased performance.

DPN_MSGID_RECEIVE
When another player sends you data, it is delivered to your message handler with a DPN_MSGID_RECEIVE message. By default, the buffer containing the data is valid only until you return from the message handler. If you want to retain control over the data buffer after your message handler returns, have your message handler return DPNSUCCESS_PENDING. This return value will prevent DirectPlay from freeing or modifying the buffer. When you no longer need the buffer, you must return it to DirectPlay's control by calling IDirectPlay8Peer::ReturnBuffer.

DPN_MSGID_PEER_INFO, DPN_MSGID_GROUP_INFO, and DPN_MSGID_APPLICATION_DESC
Information structures are associated with the application, and with each player and group in the session. If this information changes during a session, you will receive the corresponding message. To obtain up-to-date information, you must call IDirectPlay8Peer::GetApplicationDesc, IDirectPlay8Peer::GetGroupInfo, or IDirectPlay8Peer::GetPeerInfo.

DPN_MSGID_HOST_MIGRATE
A session must have a host. If the host set the DPNSESSION_MIGRATE_HOST flag when it created the session and then leaves the session without terminating it, DirectPlay chooses a new host. DirectPlay notifies the remaining players of the change by sending them a DPN_MSGID_HOST_MIGRATE message with the new host's ID.

Session Termination Messages

Sessions terminate for a variety of reasons. Typically, the session terminates when the host calls IDirectPlay8Peer::TerminateSession. If host migration is not permitted, the session terminates when the host calls IDirectPlay8Peer::Close or is involuntarily disconnected.

DPN_MSGID_TERMINATE_SESSION
The DPN_MSGID_TERMINATE_SESSION message notifies you that the session is over. It is followed by a series of DPN_MSGID_DESTROY_PLAYER, DPN_MSGID_DESTROY_GROUP, and DPN_MSGID_REMOVE_PLAYER_FROM_GROUP messages.

DPN_MSGID_DESTROY_PLAYER
You will receive a DPN_MSGID_DESTROY_PLAYER message for each player in the session. If the host has intentionally terminated the session, this is considered normal behavior and the dwReason member of the associated structure is set to DPNDESTROYPLAYERREASON_NORMAL. The DPNDESTROYPLAYERREASON_SESSIONTERMINATED value is set only for unexpected disconnections from a session that does not allow host migration.

DPN_MSGID_DESTROY_GROUP and DPN_MSGID_REMOVE_PLAYER_FROM_GROUP
If any groups have been formed, you will receive DPN_MSGID_REMOVE_PLAYER_FROM_GROUP messages for each member of each group, and a DPN_MSGID_DESTROY_GROUP message for each group itself. The DPN_MSGID_REMOVE_PLAYER_FROM_GROUP messages will always arrive before the corresponding DPN_MSGID_DESTROY_PLAYER or DPN_MSGID_DESTROY_GROUP messages.