本篇是
使用DirectPlay進(jìn)行網(wǎng)絡(luò)互聯(lián)(1)的續(xù)篇。
使用地址
一個網(wǎng)絡(luò)使用IP地址和端口來傳送數(shù)據(jù),在DirectPlay中,使用DirectPlay專用對象IDirectPlay8Address來構(gòu)造地址。
The IDirectPlay8Address interface contains generic addressing methods
used to create and manipulate addresses for Microsoft® DirectPlay® . This
interface is one of the interfaces available through the
CLSID_DirectPlay8Address COM object.
The IDirectPlay8Address interface contains the following methods.
IDirectPlay8Address Methods
|
BuildFromURLW |
BuildFromURLA |
Duplicate |
SetEqual |
IsEqual |
Clear |
GetURLW |
GetURLA |
GetSP |
GetUserData |
SetSP |
SetUserData |
GetNumComponents |
GetComponentByName |
GetComponentByIndex |
AddComponent |
GetDevice |
SetDevice |
BuildFromDPADDRESS |
Remarks
In order to deliver messages, each participant in a multiplayer game must
have a unique address. Addresses can refer either to the computer that your
application is running on (device address), or a computer that your
application needs to communicate with (host address).
DirectPlay represents addresses as URLs. These URLs are then encapsulated in
the address object so that they can be passed to or from the DirectPlay API. In
general, address URLs are strings that consist of three basic components in the
following order: scheme, scheme separator, and data string.
All DirectPlay addresses use "x-directplay" as the scheme, and ":/" as the
scheme separator. Using ":/" as a separator implies that the data that follows
is opaque. In other words, the data string does not conform to any
Internet standard, and should simply be passed on to the receiving application
without modification. All DirectPlay URLs thus have the following general form:
x-directplay:/[data string]
There are two basic approaches to handling address objects:
- Handle the data string directly, using normal string manipulation
techniques.
- Use the methods exposed by IDirectPlay8Address to obtain or
modify the individual elements of the data string.
For more information on DirectPlay addresses, see DirectPlay Addressing.
常用的
IDirectPlay8Address方法有三個:
IDirectPlay8Address::Clear |
清除所有地址數(shù)據(jù) |
IDirectPlay8Address::SetSP |
設(shè)置服務(wù)提供者 |
IDirectPlay8Address::AddComponent |
添加地址組件 |
使用地址對象之前,需要使用CoCreateInstance函數(shù)來創(chuàng)建它:
IDirectPlay8Server* g_dp_server; // DirectPlay Server
// create DirectPlay Server component
if(FAILED(CoCreateInstance(CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC, IID_IDirectPlay8Server,
(void**)&g_dp_server)))
return FALSE;
添加組件
一個地址對象只是包含Unicode文本字符串的簡單對象,該文本字符串包含服務(wù)提供者、端口號以及其他可選信息,下圖顯示了可以添加到地址對象的組件以及每個組件的數(shù)據(jù)類型:

AddComponent函數(shù)的惟一用途就是創(chuàng)建該字符串以供其他對象使用。
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.
設(shè)置服務(wù)提供者
下一步要做的就是選擇服務(wù)提供者,調(diào)用 IDirectPlay8Address::SetSP函數(shù)來設(shè)置。
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 |
選擇端口
無論是主持一次會話(作為服務(wù)器端或單點(diǎn))還是使用客戶端網(wǎng)絡(luò)模型連接到一個遠(yuǎn)程系統(tǒng),接下來必須要做的就是選擇端口,如果要連接到遠(yuǎn)程系統(tǒng),就必須知道應(yīng)用程序所使用的端口,以便能夠連接到遠(yuǎn)程系統(tǒng)以及發(fā)送數(shù)據(jù)到遠(yuǎn)程系統(tǒng)。端口號可以隨意選擇,但是不要使用保留端口號(1
-
1024),選擇1024以上的端口號會比較安全。可以通過指定端口號0而讓DirectPlay來選擇一個端口號,但是這樣做的弊病在于端口號可能為任意數(shù)字,就需要對端口號進(jìn)行查詢,推薦的做法是自己選擇一個端口號。
設(shè)置端口號使用 IDirectPlay8Address::AddComponent函數(shù)。
IDirectPlay8Address* dp_address;
DWORD port = 21234;
// Set port
if(FAILED(dp_address->AddComponent(DPNA_KEY_PORT, &port, sizeof(DWORD), DPNA_DATATYPE_DWORD)))
{
dp_address->Release();
return FALSE;
}
使用消息處理函數(shù)
消息處理回調(diào)函數(shù)非常簡單,它僅僅需要區(qū)分接收到的是哪一種消息,并盡可能快地處理消息,可以將消息處理函數(shù)想象成一個漏斗,如下圖所示:

以下是一個簡單的消息處理函數(shù)代碼實例:
//----------------------------------------------------------------------------------------
// 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
// 處理創(chuàng)建玩家
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表示處理失敗。每個消息都帶有一個數(shù)據(jù)緩沖區(qū),這些緩沖區(qū)被類型轉(zhuǎn)換為適當(dāng)?shù)慕Y(jié)構(gòu)體,除了它們是以DPNMSG_而不是DPN_MSGID_開頭之外,這些結(jié)構(gòu)體和消息宏幾乎具有相同的命名規(guī)則。
配置會話信息
每一個網(wǎng)絡(luò)對象都需要知道一些要主持或要加入的會話信息,這些信息包含在一個結(jié)構(gòu)體中:
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.
會話數(shù)據(jù)
一個服務(wù)器端需要配置允許的最大玩家數(shù)(如果需要進(jìn)行限制)、會話名稱和登陸密碼、會話標(biāo)志以及應(yīng)用程序GUID,如果不想限制最大玩家數(shù),將dwMaxPlayers字段設(shè)置為0即可。
// application GUID
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;
客戶端結(jié)構(gòu)體所需設(shè)置的信息包括要加入的會話名稱和密碼、客戶端 /
服務(wù)器端會話標(biāo)志以及應(yīng)用程序GUID。一定要使用和服務(wù)器端相同的應(yīng)用程序GUID,這樣客戶端和服務(wù)器端才能在網(wǎng)絡(luò)中找到對方。
服務(wù)器端的處理
獲得網(wǎng)絡(luò)的第一步是創(chuàng)建一個服務(wù)器端。服務(wù)器端扮演了網(wǎng)絡(luò)游戲的中央處理單元,所有玩家通過客戶端應(yīng)用程序連接到服務(wù)器端并在二者之間來回傳輸數(shù)據(jù)。服務(wù)器端保持游戲數(shù)據(jù)同步并告知玩家當(dāng)前的游戲狀態(tài),雖然對于小型網(wǎng)絡(luò)游戲而言,這并不是最快的辦法,但對于大型網(wǎng)絡(luò)游戲而言,則是最好的方法。
要創(chuàng)建服務(wù)器端,需要調(diào)用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.
以下是創(chuàng)建服務(wù)器端會話的代碼示例:
HWND g_hwnd;
// 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;
}
處理玩家
服務(wù)器端創(chuàng)建好之后,接收到的第一個消息就是創(chuàng)建一個玩家。創(chuàng)建的第一個玩家總是主機(jī)玩家,然后其他玩家才開始被創(chuàng)建和釋放,但是在整個會話過程中,主機(jī)玩家始終都存在。創(chuàng)建玩家消息通過DPN_MSGID_CREATE_PLAYER定義,并且消息緩沖區(qū)被類型轉(zhuǎn)換成
DPNMSG_CREATE_PLAYER結(jié)構(gòu)體。
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.
玩家相關(guān)數(shù)據(jù)指針pvPlayerContext是用來在應(yīng)用程序中定義玩家的信息,該數(shù)據(jù)指針可以指向一個結(jié)構(gòu)體、類實例或包含了玩家名稱、健康狀態(tài)、年齡、當(dāng)前武器以及護(hù)甲等的數(shù)據(jù)緩沖區(qū)。通過把玩家相關(guān)數(shù)據(jù)指針傳遞給DirectPlay,它就能帶來更快的訪問速度。因為時間關(guān)系,必須很快遍歷一個已登錄玩家的列表來查找一個匹配的玩家ID時,這樣做就能節(jié)省時間。
一個玩家有一個與之關(guān)聯(lián)的名稱,而且要能夠取回玩家名稱以便在游戲中使用(因為沒有人想使用一個數(shù)字作為其名稱),這就是IDirectPlay8Server::
GetClientInfo函數(shù)所實現(xiàn)的功能。
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指向玩家信息結(jié)構(gòu)體
:
Describes 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.
以下是處理創(chuàng)建玩家的代碼實例:
// 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;
}