使用DirectPlay进行网络互联(2)
使用地址
一个网络使用IP地址和端口来传送数据,在DirectPlay中,使用DirectPlay专用对象IDirectPlay8Address来构造地址。常用的 IDirectPlay8Address方法有三个:
IDirectPlay8Address::Clear | 清除所有地址数据 |
IDirectPlay8Address::SetSP | 设置服务提供者 |
IDirectPlay8Address::AddComponent | 添加地址组件 |
使用地址对象之前,需要使用CoCreateInstance函数来创建它:
// create DirectPlay Server component
if (FAILED(CoCreateInstance(CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC, IID_IDirectPlay8Server, ( void ** ) & g_dp_server)))
return FALSE;
添加组件
一个地址对象只是包含Unicode文本字符串的简单对象,该文本字符串包含服务提供者、端口号以及其他可选信息。AddComponent函数的惟一用途就是创建该字符串以供其他对象使用。
Adds a component to the address. If the component is part of the address, it is replaced by the new value in this call.
Values are specified in native formats when making this call. Therefore, the lpvData parameter should be a recast pointer to a variable that holds the data in the native format. For example, if the component is a GUID, the lpvData parameter should be a recast pointer to a GUID.
This method validates that the predefined component types are the right format.
HRESULT AddComponent(const WCHAR *const pwszName,const void *const lpvData,const DWORD dwDataSize,const DWORD dwDataType );
Parameters
- pwszName
- [in] NULL-terminated Unicode string that contains the key for the component.
- lpvData
- [in] Pointer to a buffer that contains the value associated with the specified key. Data should be specified in its native format.
- dwDataSize
-
[in] Size, in bytes, of the data in the buffer located at lpvData. The size depends on the data type. If the size is not specified correctly, the method returns DPNERR_INVALIDPARAM.
- DWORD
- Size = sizeof( DWORD )
- GUID
- Size = sizeof( GUID )
- String
- Size = size of the string in bytes, including NULL terminator.
- dwDataType
-
[in] Data type of the value associated with this key. The data type can be one of the following:
- DPNA_DATATYPE_STRING
- Data is a NULL-terminated string.
- DPNA_DATATYPE_DWORD
- Data is a DWORD.
- DPNA_DATATYPE_GUID
- Data is a GUID.
- DPNA_DATATYPE_BINARY
- Data is in raw binary format.
Return Values
Returns S_OK if successful, or one of the following error values.
DPNERR_INVALIDPARAM |
DPNERR_INVALIDPOINTER |
DPNERR_NOTALLOWED |
Remarks
See DirectPlay Addressing for a discussion of various address components and their keys.
设置服务提供者
下一步要做的就是选择服务提供者,调用 IDirectPlay8Address::SetSP函数来设置。
Sets the service provider GUID in the address object. If a service provider is specified for this address, it is overwritten by this call.
HRESULT SetSP(const GUID *const pguidSP);
Parameters
- pguidSP
- [in] Pointer to the service provider GUID.
Return Values
Returns S_OK if successful, or one of the following error values.
DPNERR_INVALIDPOINTER |
DPNERR_NOTALLOWED |
选择端口
无论是主持一次会话(作为服务器端或单点)还是使用客户端网络模型连接到一个远程系统,接下来必须要做的就是选择端口,如果要连接到远程系统,就必须知道应用程序所使用的端口,以便能够连接到远程系统以及发送数据到远程系统。端口号可以随意选择,但是不要使用保留端口号(1 - 1024),选择1024以上的端口号会比较安全。可以通过指定端口号0而让DirectPlay来选择一个端口号,但是这样做的弊病在于端口号可能为任意数字,就需要对端口号进行查询,推荐的做法是自己选择一个端口号。
设置端口号使用 IDirectPlay8Address::AddComponent函数。
DWORD port = 21234;
// Set port
if (FAILED(dp_address -> AddComponent(DPNA_KEY_PORT, & port, sizeof (DWORD), DPNA_DATATYPE_DWORD)))
{
dp_address -> Release();
return FALSE;
}
使用消息处理函数
以下是一个简单的消息处理函数代码实例:
// Callback function that receives all messages from the client, and receives indications
// of session changes from the IDirectPlay8Client interface.
// ----------------------------------------------------------------------------------------
HRESULT WINAPI Net_Msg_Handle(PVOID user_context, DWORD message_id, PVOID msg_buffer)
{
DPNMSG_CREATE_PLAYER * create_player; // contains information for the DPN_MSGID_CREATE_PLAYER system message
DPNMSG_DESTROY_PLAYER * destroy_player; // contains information for the DPN_MSGID_DESTROY_PLAYER system message
switch (message_id)
{
// Microsoft DirectPlay generates the DPN_MSGID_CREATE_PLAYER message when a player is added to a
// peer-to-peer or client/server session.
case DPN_MSGID_CREATE_PLAYER:
create_player = (DPNMSG_CREATE_PLAYER * ) msg_buffer
// 处理创建玩家
return S_OK;
// Microsoft DirectPlay generates the DPN_MSGID_DESTROY_PLAYER message when a player leaves a peer-to-peer
// or client/server session.
case DPN_MSGID_DESTROY_PLAYER:
destroy_player = (DPNMSG_DESTROY_PLAYER * ) msg_buffer;
// 处理销毁玩家
return S_OK;
}
return S_FAIL;
}
通过switch-case语句,可以快速找到要处理的消息,而略过其他消息。如果处理消息成功,就返回S_OK,否则返回E_FAIL表示处理失败。每个消息都带有一个数据缓冲区,这些缓冲区被类型转换为适当的结构体,除了它们是以DPNMSG_而不是DPN_MSGID_开头之外,这些结构体和消息宏几乎具有相同的命名规则。
配置会话信息
每一个网络对象都需要知道一些要主持或要加入的会话信息,这些信息包含在一个结构体中:
Describes the settings for a Microsoft® DirectPlay® application.
typedef struct _DPN_APPLICATION_DESC{ DWORD dwSize; DWORD dwFlags; GUID guidInstance; GUID guidApplication; DWORD dwMaxPlayers; DWORD dwCurrentPlayers; WCHAR* pwszSessionName; WCHAR* pwszPassword; PVOID pvReservedData; DWORD dwReservedDataSize; PVOID pvApplicationReservedData; DWORD dwApplicationReservedDataSize;} DPN_APPLICATION_DESC, *PDPN_APPLICATION_DESC;
Members
- dwSize
- Size of the DPN_APPLICATION_DESC structure. The application must set this member before it uses the structure.
- dwFlags
-
One of the following flags describing application behavior.
- DPNSESSION_CLIENT_SERVER
- This type of session is client/server. This flag cannot be combined with DPNSESSION_MIGRATE_HOST.
- DPNSESSION_MIGRATE_HOST
- Used in peer-to-peer sessions, enables host migration. This flag cannot be combined with DPNSESSION_CLIENT_SERVER.
- DPNSESSION_NODPNSVR
- Do not forward enumerations to your host from DPNSVR. See Using the DirectPlay DPNSVR Application for details.
- DPNSESSION_REQUIREPASSWORD
- The session is password protected. If this flag is set, pwszPassword must be a valid string.
- guidInstance
- Globally unique identifier (GUID) that is generated by DirectPlay at startup, representing the instance of this application. This member is an [out] parameter when calling the GetApplicationDesc method exposed by the IDirectPlay8Peer, IDirectPlay8Client, and IDirectPlay8Server interfaces. It is an optional [in] parameter when calling the Connect method exposed by the IDirectPlay8Peer and IDirectPlay8Client interfaces. It must be set to GUID NULL when you call the SetApplicationDesc method exposed by the IDirectPlay8Server and IDirectPlay8Peer interfaces. You cannot obtain this GUID by calling the IDirectPlay8Server::Host or IDirectPlay8Peer::Host methods. You must obtain the GUID by calling a GetApplicationDesc method.
- guidApplication
- Application GUID.
- dwMaxPlayers
- Variable of type DWORD, specifying the maximum number of players allowed in the session. Set this member to 0 to specify an unlimited number of players.
- dwCurrentPlayers
- Variable of type DWORD specifying the number of players currently connected to the session. This member is an [out] parameter that is set only by the GetApplicationDescription method exposed by IDirectPlay8Peer, IDirectPlay8Client, and IDirectPlay8Server.
- pwszSessionName
- Pointer to a variable of type WCHAR specifying the Unicode name of the session. This member is set by the host or server only for informational purposes. A client cannot use this name to connect to a host or server.
- pwszPassword
- Pointer to a variable of type WCHAR specifying the Unicode password that is required to connect to the session. This must be NULL if the DPNSESSION_REQUIREPASSWORD is not set in the dwFlags member.
- pvReservedData
- Pointer to DirectPlay reserved data. An application should never modify this value.
- dwReservedDataSize
- Variable of type DWORD specifying the size of data contained in the pvReservedData member. An application should never modify this value.
- pvApplicationReservedData
- Pointer to application-specific reserved data. This value is optional and may be set to NULL.
- dwApplicationReservedDataSize
- Variable of type DWORD specifying the size of the data in the pvApplicationReservedData member. This value is optional and may be set to 0.
Remarks
Multiple instances of the application can run simultaneously. "Application" refers to a specific instance of an application.
The dwMaxPlayers, pvApplicationReservedData, dwApplicationReservedDataSize, pwszPassword, and pwszSessionName members can be set when calling the Host or SetApplicationDesc methods exposed by the IDirectPlay8Server and IDirectPlay8Peer interfaces.
When connecting to a password protected session, the data in the pwszPassword member is transmitted in clear text to the host.
会话数据
一个服务器端需要配置允许的最大玩家数(如果需要进行限制)、会话名称和登陆密码、会话标志以及应用程序GUID,如果不想限制最大玩家数,将dwMaxPlayers字段设置为0即可。
GUID g_app_guid = { 0xababbe60 , 0x1ac0 , 0x11d5 , { 0x90 , 0x89 , 0x44 , 0x45 , 0x53 , 0x54 , 0x0 , 0x1 } };
DPN_APPLICATION_DESC app_desc; // Describes the settings for a Microsoft DirectPlay application
// Setup the application description structure
ZeroMemory( & app_desc, sizeof (DPN_APPLICATION_DESC));
app_desc.dwSize = sizeof (DPN_APPLICATION_DESC);
app_desc.dwFlags = DPNSESSION_CLIENT_SERVER;
app_desc.guidApplication = g_app_guid;
app_desc.pwszSessionName = L " SercverSession " ;
app_desc.dwMaxPlayers = 256 ;
客户端结构体所需设置的信息包括要加入的会话名称和密码、客户端 / 服务器端会话标志以及应用程序GUID。一定要使用和服务器端相同的应用程序GUID,这样客户端和服务器端才能在网络中找到对方。
服务器端的处理
获得网络的第一步是创建一个服务器端。服务器端扮演了网络游戏的中央处理单元,所有玩家通过客户端应用程序连接到服务器端并在二者之间来回传输数据。服务器端保持游戏数据同步并告知玩家当前的游戏状态,虽然对于小型网络游戏而言,这并不是最快的办法,但对于大型网络游戏而言,则是最好的方法。
要创建服务器端,需要调用IDirectPlay8Server::Host来主持会话。
Creates a new client/server session, hosted by the local computer.
HRESULT Host(const DPN_APPLICATION_DESC *const pdnAppDesc,IDirectPlay8Address **const prgpDeviceInfo,const DWORD cDeviceInfo,const DPN_SECURITY_DESC *const pdpSecurity,const DPN_SECURITY_CREDENTIALS *const pdpCredentials,VOID *const pvPlayerContext,const DWORD dwFlags);
Parameters
- pdnAppDesc
- [in] Pointer to a DPN_APPLICATION_DESC structure that describes the application.
- prgpDeviceInfo
- [in] Pointer to an array of IDirectPlay8Address objects containing device addresses that should be used to host the application.
- cDeviceInfo
- [in] Variable of type DWORD that specifies the number of device address objects in the array pointed to by prgpDeviceInfo.
- pdpSecurity
- [in] Reserved. Must be set to NULL.
- pdpCredentials
- [in] Reserved. Must be set to NULL.
- pvPlayerContext
- [in] Pointer to the context value of the player. This value is preset when the local computer handles the DPN_MSGID_CREATE_PLAYER message. This parameter is optional, and may be set to NULL.
- dwFlags
-
[in] The following flag can be specified.
- DPNHOST_OKTOQUERYFORADDRESSING
- Setting this flag will display a standard Microsoft® DirectPlay® dialog box, which queries the user for more information if not enough information is passed in this method.
Return Values
Returns S_OK if successful, or the following error value.
DPNERR_DATATOOLARGE |
DPNERR_INVALIDPARAM |
Remarks
If you set the DPNHOST_OKTOQUERYFORADDRESSING flag in dwFlags, the service provider may attempt to display a dialog box to ask the user to complete the address information. You must have a visible window present when the service provider tries to display the dialog box, or your application will lock.
The maximum size of the application data that you assign to the pvApplicationReservedData member of the DPN_APPLICATION_DESC structure is limited by the service provider's Maximum Transmission Unit. If your application data is too large, the method will fail and return DPNERR_DATATOOLARGE.
以下是创建服务器端会话的代码示例:
// application GUID
GUID g_app_guid = { 0xababbe60 , 0x1ac0 , 0x11d5 , { 0x90 , 0x89 , 0x44 , 0x45 , 0x53 , 0x54 , 0x0 , 0x1 } };
IDirectPlay8Server * g_dp_server; // DirectPlay Server
BOOL g_is_hosting; // flag indicates whether host started or not
// --------------------------------------------------------------------------------
// Start hosting a server which GUID specified by adapter_guid.
// --------------------------------------------------------------------------------
BOOL Start_Session(GUID * adapter_guid)
{
// Make sure there's an adapter
if (adapter_guid == NULL)
return FALSE;
// Need to re-assign a network handler as quitting a previous session to clears it.
// Close the connection first before assigning a new network handler.
//
// Closes the open connnection to a session.
g_dp_server -> Close( 0 );
// Initialize DirectPlay Server
if (FAILED(g_dp_server -> Initialize(NULL, Net_Msg_Handle, 0 )))
return FALSE;
IDirectPlay8Address * dp_address;
// Create an address object and fill it with information
if (FAILED(CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC, IID_IDirectPlay8Address, ( void ** ) & dp_address)))
return FALSE;
// Set the protocol to TCP/IP
//
// Sets the service provider GUID in the address object.
// If a service provider is specified for this address, it is overwrittern by this call.
if (FAILED(dp_address -> SetSP( & CLSID_DP8SP_TCPIP)))
{
dp_address -> Release();
return FALSE;
}
// Set the port
DWORD port = 21234 ;
// Adds a component to the address.
// If the component is part of the address, it is replaced by the new value in this call.
// Set port
if (FAILED(dp_address -> AddComponent(DPNA_KEY_PORT, & port, sizeof (DWORD), DPNA_DATATYPE_DWORD)))
{
dp_address -> Release();
return FALSE;
}
// Set the adapter
if (FAILED(dp_address -> AddComponent(DPNA_KEY_DEVICE, adapter_guid, sizeof (GUID), DPNA_DATATYPE_GUID)))
{
dp_address -> Release();
return FALSE;
}
DPN_APPLICATION_DESC app_desc; // Describes the settings for a Microsoft DirectPlay application
// Setup the application description structure
ZeroMemory( & app_desc, sizeof (DPN_APPLICATION_DESC));
app_desc.dwSize = sizeof (DPN_APPLICATION_DESC);
app_desc.dwFlags = DPNSESSION_CLIENT_SERVER;
app_desc.guidApplication = g_app_guid;
app_desc.pwszSessionName = L " SercverSession " ;
app_desc.dwMaxPlayers = 256 ;
// Start hosting
//
// Creates a new client/server session, hosted by the local computer.
if (FAILED(g_dp_server -> Host( & app_desc, & dp_address, 1 , NULL, NULL, NULL, 0 )))
{
dp_address -> Release();
return FALSE;
}
// Release the address component
dp_address -> Release();
// Disables combo-box control.
//
// Enables or disables mouse and keyboard input to the specified window or control.
// When input is disabled, the window does not receive input such as mouse clicks and key presses.
// When input is enabled, the window receives all input.
EnableWindow(GetDlgItem(g_hwnd, IDC_ADAPTERS), FALSE);
// Setup the dialog information
SetWindowText(GetDlgItem(g_hwnd, IDC_STARTSTOP), " Stop " );
g_is_hosting = TRUE;
return TRUE;
}
处理玩家
服务器端创建好之后,接收到的第一个消息就是创建一个玩家。创建的第一个玩家总是主机玩家,然后其他玩家才开始被创建和释放,但是在整个会话过程中,主机玩家始终都存在。创建玩家消息通过DPN_MSGID_CREATE_PLAYER定义,并且消息缓冲区被类型转换成 DPNMSG_CREATE_PLAYER结构体。
Microsoft® DirectPlay® generates the DPN_MSGID_CREATE_PLAYER message when a player is added to a peer-to-peer or client/server session.
The DPNMSG_CREATE_PLAYER structure contains information for the DPN_MSGID_CREATE_PLAYER system message.
typedef struct _DPNMSG_CREATE_PLAYER{ DWORD dwSize; DPNID dpnidPlayer; PVOID pvPlayerContext;} DPNMSG_CREATE_PLAYER, *PDPNMSG_CREATE_PLAYER;
- dwSize
- Size of this structure.
- dpnidPlayer
- DPNID of the player that was added to the session.
- pvPlayerContext
- Player context value.
Return Values
Return DPN_OK.
Remarks
The only method of setting the player context value is through this system message. You can either set the player context value directly, through this message, or indirectly through DPN_MSGID_INDICATE_CONNECT. Once a player context value has been set, it cannot be changed.
玩家相关数据指针pvPlayerContext是用来在应用程序中定义玩家的信息,该数据指针可以指向一个结构体、类实例或包含了玩家名称、健康状态、年龄、当前武器以及护甲等的数据缓冲区。通过把玩家相关数据指针传递给DirectPlay,它就能带来更快的访问速度。因为时间关系,必须很快遍历一个已登录玩家的列表来查找一个匹配的玩家ID时,这样做就能节省时间。
一个玩家有一个与之关联的名称,而且要能够取回玩家名称以便在游戏中使用(因为没有人想使用一个数字作为其名称),这就是IDirectPlay8Server:: GetClientInfo函数所实现的功能。
Retrieves the client information set for the specified client.
HRESULT GetClientInfo(const DPNID dpnid,DPN_PLAYER_INFO *const pdpnPlayerInfo,DWORD *const pdwSize,const DWORD dwFlags);
Parameters
- dpnid
- [in] Variable of type DPNID that specifies the identifier of the client to retrieve the information for.
- pdpnPlayerInfo
- [out] Pointer to a DPN_PLAYER_INFO structure that is filled with client information. If pdwSize is not set to NULL, you must set pdpnPlayerInfo.dwSize to an appropriate value.
- pdwSize
- [in,out] Pointer to a variable of type DWORD that contains the size of the client data, in bytes, returned in the pdpnPlayerInfo parameter. If the buffer is too small, this method returns DPNERR_BUFFERTOOSMALL and this parameter contains the size of the required buffer.
- dwFlags
-
[in] Flags describing the information returned for the client. Currently, both of the following flags are returned.
- DPNINFO_NAME
- The DPN_PLAYER_INFO structure contains the name set for the client.
- DPNINFO_DATA
- The DPN_PLAYER_INFO structure contains the data set for the client.
Return Values
Returns S_OK if successful, or one of the following error values.
DPNERR_BUFFERTOOSMALL |
DPNERR_INVALIDPARAM |
DPNERR_INVALIDPLAYER |
Remarks
Call this method after the server receives a DPN_MSGID_CLIENT_INFO message from the application. This message indicates that a client has updated its information.
Microsoft® DirectPlay® returns the DPN_PLAYER_INFO structure, and the pointers assigned to the structure's pwszName and pvData members in a contiguous buffer. If the two pointers were set, you must have allocated enough memory for the structure, plus the two pointers. The most robust way to use this method is to first call it with pdwSize set to NULL. When the method returns, pdwSize will point to the correct value. Use that value to allocate memory for the structure and call the method a second time to retrieve the information.
When the method returns, the dwInfoFlags member of the DPN_PLAYER_INFO structure will always have the DPNINFO_DATA and DPNINFO_NAME flags set, even if the corresponding pointers are set to NULL. These flags are used when calling IDirectPlay8Client::SetClientInfo, to notify DirectPlay of which values have changed.
Transmission of nonstatic information should be handled with the IDirectPlay8Client::Send method because of the high cost of using the IDirectPlay8Client::SetPeerInfo method.
The player sets the information by calling IDirectPlay8Client::SetClientInfo.
pdpnPlayerInfo指向玩家信息结构体。
Describe static player information.
typedef struct _DPN_PLAYER_INFO{ DWORD dwSize; DWORD dwInfoFlags; PWSTR pwszName; PVOID pvData; DWORD dwDataSize; DWORD dwPlayerFlags; } DPN_PLAYER_INFO, *PDPN_PLAYER_INFO;
Members
- dwSize
- Variable of type DWORD describing the size of this structure.
- dwInfoFlags
-
Variable of type DWORD containing flags that specify the type of information contained in this structure. When a GetPlayerInfo method returns, the dwInfoFlags member of the DPN_PLAYER_INFO will always have both flags set, even if the corresponding pointers are set to NULL. These flags are used when calling IDirectPlay8Peer::SetPeerInfo, to notify Microsoft® DirectPlay® which values have changed.
- DPNINFO_NAME
- The pwszName member contains valid data.
- DPNINFO_DATA
- The pvData member contains valid data.
- pwszName
- Pointer to a variable of type PWSTR specifying the Unicode name of the player.
- pvData
- Pointer to the data describing the player.
- dwDataSize
- Variable of type DWORD that specifies the size of the data contained in the pvData member.
- dwPlayerFlags
-
Variable of type DWORD that may contain one of the following flags.
- DPNPLAYER_LOCAL
- This information is for the local player.
- DPNPLAYER_HOST
- This player is the host for the application.
Remarks
When using this structure in the IDirectPlay8Peer::GetPeerInfo and IDirectPlay8Server::GetClientInfo methods, dwInfoFlags must be set to 0.
When using this structure in the IDirectPlay8Client::SetClientInfo, IDirectPlay8Peer::SetPeerInfo, or IDirectPlay8Server::SetServerInfo methods, dwPlayerFlags should be set to zero.
以下是处理创建玩家的代码实例:
// application variables
struct PLAYER_INFO
{
DPNID player_id; // DirectPlay Player ID
char name[ 26 ]; // Player Name
PLAYER_INFO() { player_id = 0 ; }
};
// window handles, class.
HWND g_hwnd;
char g_class_name[] = " ServerClass " ;
// application GUID
GUID g_app_guid = { 0xababbe60 , 0x1ac0 , 0x11d5 , { 0x90 , 0x89 , 0x44 , 0x45 , 0x53 , 0x54 , 0x0 , 0x1 } };
IDirectPlay8Server * g_dp_server; // DirectPlay Server
DPN_SERVICE_PROVIDER_INFO * g_adapter_list; // adapters
DWORD g_num_adapters; // number of adapters
PLAYER_INFO g_player_info[ 256 ]; // player information
BOOL g_is_hosting; // flag indicates whether host started or not
// ----------------------------------------------------------------------------------------
// Callback function that receives all messages from the client, and receives indications
// of session changes from the IDirectPlay8Client interface.
// ----------------------------------------------------------------------------------------
HRESULT WINAPI Net_Msg_Handle(PVOID user_context, DWORD message_id, PVOID msg_buffer)
{
DPNMSG_CREATE_PLAYER * create_player; // contains information for the DPN_MSGID_CREATE_PLAYER system message
DPNMSG_DESTROY_PLAYER * destroy_player; // contains information for the DPN_MSGID_DESTROY_PLAYER system message
DPNMSG_RECEIVE * receive_data; // contains information for the DPN_MSGID_RECEIVE system message
DPN_PLAYER_INFO * dpn_player_info; // describes static player informaion
DPN_BUFFER_DESC buffer_desc; // used dy DirectPlay for generic buffer information
DPNHANDLE async_handle;
PLAYER_INFO * player_info;
int index;
DWORD size;
char message[ 512 ];
HRESULT rv;
switch (message_id)
{
// Microsoft DirectPlay generates the DPN_MSGID_CREATE_PLAYER message when a player is added to a
// peer-to-peer or client/server session.
case DPN_MSGID_CREATE_PLAYER:
create_player = (DPNMSG_CREATE_PLAYER * ) msg_buffer;
// get player name and save it
size = 0 ;
dpn_player_info = NULL;
// Retrieves the client information set for the specified client
rv = g_dp_server -> GetClientInfo(create_player -> dpnidPlayer, dpn_player_info, & size, 0 );
if (FAILED(rv) && rv != DPNERR_BUFFERTOOSMALL)
{
// skip this if this is a host player
if (rv == DPNERR_INVALIDPLAYER)
break ;
return E_FAIL;
}
if ((dpn_player_info = (DPN_PLAYER_INFO * ) new BYTE[size]) == NULL)
return E_FAIL;
ZeroMemory(dpn_player_info, size);
dpn_player_info -> dwSize = sizeof (DPN_PLAYER_INFO);
// retrieves the client information set again
if (FAILED(g_dp_server -> GetClientInfo(create_player -> dpnidPlayer, dpn_player_info, & size, 0 )))
{
delete[] dpn_player_info;
return E_FAIL;
}
// Find an empty player structure to use
index = - 1 ;
for ( int i = 0 ; i < 256 ; i ++ )
{
if (g_player_info[i].player_id == 0 )
{
index = i;
break ;
}
}
if (index == - 1 )
{
delete[] dpn_player_info;
return E_FAIL;
}
// set player context pointer
create_player -> pvPlayerContext = ( void * ) & g_player_info[index];
// save player ID
g_player_info[index].player_id = create_player -> dpnidPlayer;
wcstombs(g_player_info[index].name, dpn_player_info -> pwszName, 256 );
// add player to list
SendMessage(GetDlgItem(g_hwnd, IDC_USERS), LB_ADDSTRING, 0 , (LPARAM) g_player_info[index].name);
// send a message to all players notifying someone joined
sprintf(message, " %s joined! " , g_player_info[index].name);
Send_Text_Msg(DPNID_ALL_PLAYERS_GROUP, message);
delete[] dpn_player_info;
break ;
}
// return S_OK to signify the message was handled OK.
return S_OK;
}
转载于:https://my.oschina.net/riseworlds/blog/697162
使用DirectPlay进行网络互联(2)相关推荐
- 使用DirectPlay进行网络互联(4)
客户端的处理 客户端并不像服务器端那么复杂,它通常只使用两种消息,即接收数据和终止会话消息,以及需要连接和保持单一连接(服务器端).另外最主要的就是客户端应用程序必须指定其玩家的位置,以便主机能够检索 ...
- 使用DirectPlay进行网络互联(3)
销毁玩家 当玩家断开连接时,服务器端会收到消息 DPN_MSGID_DESTROY_PLAYER,这时需要将消息缓冲区转换为DPNMSG_DESTROY_PLAYER类型. The DPNMSG_DE ...
- [渝粤教育] 苏州大学文正学院 网络互联技术与实践 参考 资料
教育 -网络互联技术与实践-章节资料考试资料-苏州大学文正学院[] 计算机网络互联设备随堂测验 1.[单选题]网桥处理的是 A.脉冲信号 B.MAC 帧 C.IP 包 D.ATM 包 参考资料[ ] ...
- 计算机网络学习笔记(六)——网络层、虚电路和数据报交换、路由(距离矢量、链路状态算法)、IP编址、网络拥塞控制、网络互联
文章目录 前言 概念 一.网络层相关概述 (一)三大核心功能 (二)通信两大阵营 二.交换技术 (一)交换技术的分类 (二)电路交换和分组交换 (三)虚电路与数据报 三.路由 (一)路由功能概述 (二 ...
- #考研#计算机文化知识1(局域网及网络互联)
局域网 掌握:局域网的概念.特点和组成:局域网的拓扑结构.参考模型:以太网的基本类型和原理 局域网的定义 狭义局域网:一个广播体系所波及范围内的网络.这是最小定义的局域网. 广义局域网:通信线路属于网 ...
- 某学校有计算机主机1300台,网络互联技术与实践第14章:构建基于静态路由的多层网络.ppt...
网络互联技术与实践第14章:构建基于静态路由的多层网络 * * * * * * * * * * 14.5 扩展知识 14.5.3 中小型园区网设计 2. 中型园区网 FE连接客户机 第3层交换 第2层 ...
- 网络协议从入门到底层原理(3)网络互联模型、物理层、数据链路层(CSMA/CD协议、Ethernet V2帧、PPP协议)
网络协议从入门到底层原理 网络互联模型(了解请求过程.网络分层) 物理层(Physical) 数字信号.模拟信号 数据通信模型 信道(单工.半双工.全双工) 数据链路层(Data Link) 封装成帧 ...
- 4 转推流格式_网络互联互通直播系统 分会场直播一体机 各地连线直播推流
网络互联互通直播系统 分会场直播一体机 各地连线直播推流 LiveMix Cloud无线互联系统完全满足广大客户通过互联网互动制作的需求,可以大大节省制作成本,提高系统延展性,可以远程连接手机或者摄像 ...
- 《CCNA学习指南:数据中心(640-911)》——2.2 网络互联模型
本节书摘来自异步社区<CCNA学习指南:数据中心(640-911)>一书中的第2章,第2.2节,作者: [美]Gary R. Wright(加里 R.赖特) , W. Richard St ...
最新文章
- 特殊标记字段(#)实时富文本显示
- RemoveError: 'setuptools' is a dependency of conda and cannot be removed from
- JavaScript 类型总览(图)
- python第三周笔记_Python第三周 学习笔记(1)
- 机器学习效率正在超越摩尔定律
- MySQL之性能优化解说
- 前端学习(1350):用户的增删改查操作7增删改查
- python求解不等式组_解线性方程组和线性不等式组
- java编写系统登录界面_java 登陆界面怎么写,连接数据库后
- 15 个第三方Web 表单资源
- 欧拉回路基本概念+判断+求解
- springmvc重定向之后取值的几种办法以及优劣比较
- mysql都有什么基本函数_【第七章】MySQL的基本函数
- 如何检查正在运行脚本的Python版本?
- IDC:2017年全球公有云服务开支将达1225亿美元
- DOS的一个小工具 LOIC
- 深度学习中的多任务学习介绍
- element-ui走马灯使用心得
- 使用mock模拟数据,实现图片文字向上的轮播
- 杂志风城市夜景PPT模板
热门文章
- 学习各位前辈开个blog
- linux下编译isl,GCC编译器升级./configure报错“configure: error: Unable to find a usable ISL.”解决办法...
- 决策树(Decision Tree)算法 python简单实现
- linux如何运行synaptic,在Debian系统中安装Synaptic和使用Synaptic修复损坏的包
- ratelimiter php,RateLimiter的 SmoothBursty(非warmup预热)及SmoothWarmingUp(预热,冷启动)...
- 智慧解析第09课:路西法祭品
- 输入一个整数将其倒着输出,如54321——12345。
- python读-Python之文件读写
- springboot Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory
- C#+winform登陆界面案例