|Microsoft DirectX 9.0|
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.
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.
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 IDirectPlay8Peer::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.
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.
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.
During a game, you might receive any of the following messages.
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.
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.
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.
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.
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 DPNERR_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 the control of DirectPlay by calling IDirectPlay8Peer::ReturnBuffer.
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.
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 identifier (ID).
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.
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.
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.
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.